1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "SharedDbUrlUtils.h"
23
24 #include <U2Core/AppContext.h>
25 #include <U2Core/Folder.h>
26 #include <U2Core/Settings.h>
27 #include <U2Core/U2DbiUtils.h>
28 #include <U2Core/U2ObjectDbi.h>
29 #include <U2Core/U2ObjectTypeUtils.h>
30 #include <U2Core/U2SafePoints.h>
31
32 #include <U2Lang/BaseTypes.h>
33
34 namespace U2 {
35
36 const QString SharedDbUrlUtils::DB_PROVIDER_SEP = ">";
37 const QString SharedDbUrlUtils::DB_URL_SEP = ",";
38 const QString SharedDbUrlUtils::DB_OBJ_ID_SEP = ":";
39
40 namespace {
41
42 const QString CONN_SETTINGS_PATH = "/shared_database/recent_connections/";
43
checkFolderPath(const QString & folderPath)44 bool checkFolderPath(const QString &folderPath) {
45 return !folderPath.isEmpty() && folderPath.startsWith(U2ObjectDbi::ROOT_FOLDER);
46 }
47
disassembleObjectId(const QString & objUrl,QStringList & idParts)48 bool disassembleObjectId(const QString &objUrl, QStringList &idParts) {
49 SAFE_POINT(SharedDbUrlUtils::isDbObjectUrl(objUrl), "Invalid shared DB object URL", false);
50 const QString fullObjId = objUrl.mid(objUrl.indexOf(SharedDbUrlUtils::DB_URL_SEP) + 1);
51 idParts.clear();
52 const int firstSepPos = fullObjId.indexOf(SharedDbUrlUtils::DB_OBJ_ID_SEP);
53 SAFE_POINT(-1 != firstSepPos, "Invalid object DB URL", false);
54 idParts.append(fullObjId.left(firstSepPos));
55
56 const int secondSepPos = fullObjId.indexOf(SharedDbUrlUtils::DB_OBJ_ID_SEP, firstSepPos + 1);
57 SAFE_POINT(-1 != secondSepPos, "Invalid object DB URL", false);
58 SAFE_POINT(fullObjId.size() - 2 >= secondSepPos, "Invalid object DB URL", false);
59 idParts.append(fullObjId.mid(firstSepPos + 1, secondSepPos - firstSepPos - 1));
60 idParts.append(fullObjId.mid(secondSepPos + 1));
61
62 return true;
63 }
64
str2Int(const QString & str,qint64 & res)65 bool str2Int(const QString &str, qint64 &res) {
66 bool conversionOk = false;
67 res = str.toLongLong(&conversionOk);
68 return conversionOk;
69 }
70
str2DataType(const QString & str,U2DataType & res)71 bool str2DataType(const QString &str, U2DataType &res) {
72 bool conversionOk = false;
73 // hope that "U2DataType" typedef won't change
74 SAFE_POINT(sizeof(U2DataType) == sizeof(qint16), "Unexpected data type detected", false);
75 res = str.toUShort(&conversionOk);
76 return conversionOk;
77 }
78
objId2Str(const U2DataId & objId,const QString & objName)79 QString objId2Str(const U2DataId &objId, const QString &objName) {
80 const qint64 idNumber = U2DbiUtils::toDbiId(objId);
81 const U2DataType objType = U2DbiUtils::toType(objId);
82 return QString::number(idNumber) + SharedDbUrlUtils::DB_OBJ_ID_SEP + QString::number(objType) + SharedDbUrlUtils::DB_OBJ_ID_SEP + objName;
83 }
84
85 } // namespace
86
createDbUrl(const U2DbiRef & dbiRef)87 QString SharedDbUrlUtils::createDbUrl(const U2DbiRef &dbiRef) {
88 SAFE_POINT(dbiRef.isValid(), "Invalid DBI reference", QString());
89 return dbiRef.dbiFactoryId + DB_PROVIDER_SEP + dbiRef.dbiId;
90 }
91
validateDbUrl(const QString & dbUrl)92 bool SharedDbUrlUtils::validateDbUrl(const QString &dbUrl) {
93 QString hostName;
94 int portNum;
95 QString dbName;
96 return U2DbiUtils::parseDbiUrl(dbUrl, hostName, portNum, dbName);
97 }
98
createDbFolderUrl(const Folder & folder,const U2DataType & compatibleType)99 QString SharedDbUrlUtils::createDbFolderUrl(const Folder &folder, const U2DataType &compatibleType) {
100 Document *doc = folder.getDocument();
101 CHECK(nullptr != doc, QString());
102 const U2DbiRef dbiRef = doc->getDbiRef();
103 CHECK(dbiRef.isValid(), QString());
104
105 const QString folderPath = folder.getFolderPath();
106 CHECK(checkFolderPath(folderPath), QString());
107
108 return dbiRef.dbiFactoryId + DB_PROVIDER_SEP + dbiRef.dbiId + DB_URL_SEP + QString::number(compatibleType) + DB_OBJ_ID_SEP + folderPath;
109 }
110
createDbFolderUrl(const QString & dbUrl,const QString & path,const U2DataType & compatibleType)111 QString SharedDbUrlUtils::createDbFolderUrl(const QString &dbUrl, const QString &path, const U2DataType &compatibleType) {
112 SAFE_POINT(validateDbUrl(dbUrl), "Invalid DB URL", QString());
113 SAFE_POINT(!path.isEmpty(), "Invalid DB folder path", QString());
114
115 return dbUrl + DB_URL_SEP + QString::number(compatibleType) + DB_OBJ_ID_SEP + path;
116 }
117
isDbFolderUrl(const QString & url)118 bool SharedDbUrlUtils::isDbFolderUrl(const QString &url) {
119 const int dbProviderSepPos = url.indexOf(DB_PROVIDER_SEP);
120 if (dbProviderSepPos < 1) {
121 return false;
122 }
123
124 const int dbUrlSepPos = url.indexOf(DB_URL_SEP, dbProviderSepPos);
125 if (-1 == dbUrlSepPos) {
126 return false;
127 }
128
129 const int dbObjTypeSepPos = url.indexOf(DB_OBJ_ID_SEP, dbUrlSepPos);
130 if (-1 == dbObjTypeSepPos || url.size() - 2 < dbObjTypeSepPos || U2ObjectDbi::ROOT_FOLDER != url[dbObjTypeSepPos + 1]) {
131 return false;
132 } else {
133 return true;
134 }
135 }
136
createDbObjectUrl(const GObject * obj)137 QString SharedDbUrlUtils::createDbObjectUrl(const GObject *obj) {
138 SAFE_POINT(nullptr != obj, "Invalid object", QString());
139 const U2EntityRef entityRef = obj->getEntityRef();
140 return createDbObjectUrl(entityRef.dbiRef, entityRef.entityId, obj->getGObjectName());
141 }
142
createDbObjectUrl(const U2DbiRef & dbiRef,const U2DataId & objId,const QString & objName)143 QString SharedDbUrlUtils::createDbObjectUrl(const U2DbiRef &dbiRef, const U2DataId &objId, const QString &objName) {
144 SAFE_POINT(dbiRef.isValid(), "Invalid database reference detected", QString());
145 SAFE_POINT(!objId.isEmpty(), "Invalid DB object reference detected", QString());
146 SAFE_POINT(!objName.isEmpty(), "Invalid DB object name detected", QString());
147
148 return dbiRef.dbiFactoryId + DB_PROVIDER_SEP + dbiRef.dbiId + DB_URL_SEP + objId2Str(objId, objName);
149 }
150
createDbObjectUrl(const QString & dbUrl,qint64 objId,const QString & objType,const QString & objName)151 QString SharedDbUrlUtils::createDbObjectUrl(const QString &dbUrl, qint64 objId, const QString &objType, const QString &objName) {
152 SAFE_POINT(validateDbUrl(dbUrl), "Invalid DB URL", QString());
153 const U2DataType objDataType = BaseTypes::toDataType(objType);
154 SAFE_POINT(U2Type::Unknown != objDataType, "Invalid object type detected", QString());
155 SAFE_POINT(!objName.isEmpty(), "Invalid DB object name", QString());
156
157 return dbUrl + DB_URL_SEP + QString::number(objId) + DB_OBJ_ID_SEP + QString::number(objDataType) + DB_OBJ_ID_SEP + objName;
158 }
159
160 namespace {
161
getSeparatorIndices(const QString & entityUrl,int & dbProviderSepPos,int & dbUrlSepPos)162 bool getSeparatorIndices(const QString &entityUrl, int &dbProviderSepPos, int &dbUrlSepPos) {
163 dbProviderSepPos = entityUrl.indexOf(SharedDbUrlUtils::DB_PROVIDER_SEP);
164 CHECK(dbProviderSepPos >= 1, false);
165
166 dbUrlSepPos = entityUrl.indexOf(SharedDbUrlUtils::DB_URL_SEP, dbProviderSepPos);
167 CHECK(dbUrlSepPos != -1, false);
168
169 return true;
170 }
171
172 } // namespace
173
isDbObjectUrl(const QString & url)174 bool SharedDbUrlUtils::isDbObjectUrl(const QString &url) {
175 int dbProviderSepPos = -1;
176 int dbUrlSepPos = -1;
177 CHECK(getSeparatorIndices(url, dbProviderSepPos, dbUrlSepPos), false);
178
179 const int dbObjIdSepPos = url.indexOf(DB_OBJ_ID_SEP, dbUrlSepPos);
180 CHECK(-1 != dbObjIdSepPos, false);
181
182 const int dbObjTypeSepPos = url.indexOf(DB_OBJ_ID_SEP, dbObjIdSepPos + 1);
183 if (-1 == dbObjTypeSepPos || url.size() - 2 < dbObjTypeSepPos) {
184 return false;
185 } else {
186 return true;
187 }
188 }
189
getDbRefFromEntityUrl(const QString & url)190 U2DbiRef SharedDbUrlUtils::getDbRefFromEntityUrl(const QString &url) {
191 int dbProviderSepPos = -1;
192 int dbUrlSepPos = -1;
193 getSeparatorIndices(url, dbProviderSepPos, dbUrlSepPos);
194 CHECK(-1 != dbProviderSepPos, U2DbiRef());
195
196 return U2DbiRef(url.left(dbProviderSepPos), url.mid(dbProviderSepPos + 1, -1 != dbUrlSepPos ? dbUrlSepPos - dbProviderSepPos - 1 : -1));
197 }
198
getKnownDbs()199 QVariantMap SharedDbUrlUtils::getKnownDbs() {
200 QVariantMap result;
201 Settings *appSettings = AppContext::getSettings();
202 const QStringList recentList = appSettings->getAllKeys(CONN_SETTINGS_PATH);
203 foreach (const QString &shortName, recentList) {
204 // TODO: fix this when other DB providers emerge
205 result.insert(shortName, MYSQL_DBI_ID + DB_PROVIDER_SEP + appSettings->getValue(CONN_SETTINGS_PATH + shortName).toString());
206 }
207 return result;
208 }
209
getDbUrlFromEntityUrl(const QString & url)210 QString SharedDbUrlUtils::getDbUrlFromEntityUrl(const QString &url) {
211 int dbProviderSepPos = -1;
212 int dbUrlSepPos = -1;
213 CHECK(getSeparatorIndices(url, dbProviderSepPos, dbUrlSepPos), QString());
214
215 return url.left(dbUrlSepPos);
216 }
217
getDbShortNameFromEntityUrl(const QString & url)218 QString SharedDbUrlUtils::getDbShortNameFromEntityUrl(const QString &url) {
219 const QString dbUrl = getDbRefFromEntityUrl(url).dbiId;
220 CHECK(!dbUrl.isEmpty(), url);
221 Settings *appSettings = AppContext::getSettings();
222 const QStringList recentList = appSettings->getAllKeys(CONN_SETTINGS_PATH);
223 foreach (const QString &shortName, recentList) {
224 if (dbUrl == appSettings->getValue(CONN_SETTINGS_PATH + shortName).toString()) {
225 return shortName;
226 }
227 }
228 return dbUrl;
229 }
230
saveNewDbConnection(const QString & connectionName,const QString & connectionUrl)231 void SharedDbUrlUtils::saveNewDbConnection(const QString &connectionName, const QString &connectionUrl) {
232 SAFE_POINT(!connectionName.isEmpty() && !connectionUrl.isEmpty(), "Unexpected DB connection", );
233 AppContext::getSettings()->setValue(CONN_SETTINGS_PATH + connectionName, connectionUrl);
234 }
235
getObjectIdByUrl(const QString & objUrl)236 U2DataId SharedDbUrlUtils::getObjectIdByUrl(const QString &objUrl) {
237 QStringList objIdParts;
238 CHECK(disassembleObjectId(objUrl, objIdParts), U2DataId());
239
240 qint64 idNumber = 0;
241 CHECK(str2Int(objIdParts[0], idNumber), U2DataId());
242
243 U2DataType dataType = U2Type::Unknown;
244 CHECK(str2DataType(objIdParts[1], dataType), U2DataId());
245
246 return U2DbiUtils::toU2DataId(idNumber, dataType);
247 }
248
getObjectNumberIdByUrl(const QString & url)249 qint64 SharedDbUrlUtils::getObjectNumberIdByUrl(const QString &url) {
250 QStringList objIdParts;
251 CHECK(disassembleObjectId(url, objIdParts), -1);
252
253 qint64 idNumber = 0;
254 CHECK(str2Int(objIdParts[0], idNumber), -1);
255
256 return idNumber;
257 }
258
getDbObjectTypeByUrl(const QString & objUrl)259 GObjectType SharedDbUrlUtils::getDbObjectTypeByUrl(const QString &objUrl) {
260 QStringList objIdParts;
261 CHECK(disassembleObjectId(objUrl, objIdParts), GObjectType());
262
263 U2DataType dataType = U2Type::Unknown;
264 CHECK(str2DataType(objIdParts[1], dataType), GObjectType());
265
266 return U2ObjectTypeUtils::toGObjectType(dataType);
267 }
268
getDbSerializedObjectTypeByUrl(const QString & url)269 QString SharedDbUrlUtils::getDbSerializedObjectTypeByUrl(const QString &url) {
270 QStringList objIdParts;
271 CHECK(disassembleObjectId(url, objIdParts), QString());
272
273 U2DataType dataType = U2Type::Unknown;
274 CHECK(str2DataType(objIdParts[1], dataType), QString());
275 return BaseTypes::toTypeId(dataType);
276 }
277
getDbObjectNameByUrl(const QString & objUrl)278 QString SharedDbUrlUtils::getDbObjectNameByUrl(const QString &objUrl) {
279 QStringList objIdParts;
280 CHECK(disassembleObjectId(objUrl, objIdParts), QString());
281
282 return objIdParts[2];
283 }
284
getObjEntityRefByUrl(const QString & url)285 U2EntityRef SharedDbUrlUtils::getObjEntityRefByUrl(const QString &url) {
286 return U2EntityRef(getDbRefFromEntityUrl(url), getObjectIdByUrl(url));
287 }
288
getDbFolderPathByUrl(const QString & url)289 QString SharedDbUrlUtils::getDbFolderPathByUrl(const QString &url) {
290 SAFE_POINT(isDbFolderUrl(url), "Invalid DB folder URL", QString());
291
292 const QString path = url.mid(url.indexOf(DB_OBJ_ID_SEP, url.indexOf(DB_URL_SEP) + 1) + 1);
293 SAFE_POINT(!path.isEmpty(), "Invalid shared DB folder URL", QString());
294
295 return path;
296 }
297
298 namespace {
299
getDbFolderDataTypeStr(const QString & url)300 QString getDbFolderDataTypeStr(const QString &url) {
301 SAFE_POINT(SharedDbUrlUtils::isDbFolderUrl(url), "Invalid DB folder URL", QString());
302
303 const int dbUrlSepPos = url.indexOf(SharedDbUrlUtils::DB_URL_SEP);
304 const QString typeStr = url.mid(dbUrlSepPos + 1, url.indexOf(SharedDbUrlUtils::DB_OBJ_ID_SEP, dbUrlSepPos + 1) - dbUrlSepPos - 1);
305 SAFE_POINT(!typeStr.isEmpty(), "Invalid shared DB folder data type", QString());
306
307 return typeStr;
308 }
309
310 } // namespace
311
getDbFolderDataTypeByUrl(const QString & url)312 U2DataType SharedDbUrlUtils::getDbFolderDataTypeByUrl(const QString &url) {
313 bool ok = false;
314 const U2DataType result = getDbFolderDataTypeStr(url).toUShort(&ok);
315 SAFE_POINT(ok, "Invalid DB folder data type", U2Type::Unknown);
316 return result;
317 }
318
getDbFolderSerializedDataTypeByUrl(const QString & url)319 QString SharedDbUrlUtils::getDbFolderSerializedDataTypeByUrl(const QString &url) {
320 return BaseTypes::toTypeId(getDbFolderDataTypeByUrl(url));
321 }
322
323 } // namespace U2
324