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 "RawDataUdrSchema.h"
23
24 #include <U2Core/AppContext.h>
25 #include <U2Core/U2DbiPackUtils.h>
26 #include <U2Core/U2DbiUtils.h>
27 #include <U2Core/U2ObjectDbi.h>
28 #include <U2Core/U2SafePoints.h>
29 #include <U2Core/UdrDbi.h>
30 #include <U2Core/UdrSchemaRegistry.h>
31
32 namespace U2 {
33
34 const UdrSchemaId RawDataUdrSchema::ID("RawData");
35
36 namespace {
37 // Fields numbers
38 const int CONTENT = 1;
39 const int SERIALIZER = 2;
40
41 const int BUFFER_SIZE = 4 * 1024 * 1024;
42
43 class DbiHelper {
44 Q_DISABLE_COPY(DbiHelper)
45
46 DbiConnection *con;
47
48 public:
DbiHelper(const U2DbiRef & dbiRef,U2OpStatus & os)49 DbiHelper(const U2DbiRef &dbiRef, U2OpStatus &os)
50 : dbi(nullptr) {
51 con = new DbiConnection(dbiRef, os);
52 CHECK_OP(os, );
53 SAFE_POINT_EXT(nullptr != con->dbi, os.setError("NULL DBI"), );
54 dbi = con->dbi->getUdrDbi();
55 SAFE_POINT_EXT(nullptr != dbi, os.setError("NULL source UDR DBI"), );
56 }
57
~DbiHelper()58 ~DbiHelper() {
59 delete con;
60 }
61
62 UdrDbi *dbi;
63 };
64
getRecordId(UdrDbi * dbi,const U2DataId & objId,U2OpStatus & os)65 UdrRecordId getRecordId(UdrDbi *dbi, const U2DataId &objId, U2OpStatus &os) {
66 const QList<UdrRecord> records = dbi->getObjectRecords(RawDataUdrSchema::ID, objId, os);
67 CHECK_OP(os, UdrRecordId("", ""));
68 CHECK_EXT(1 == records.size(), os.setError("Unexpected records count"), UdrRecordId("", ""));
69 return records.first().getId();
70 }
71
retrieveObject(UdrDbi * dbi,U2RawData & object,U2OpStatus & os)72 UdrRecordId retrieveObject(UdrDbi *dbi, U2RawData &object, U2OpStatus &os) {
73 UdrRecordId recId = getRecordId(dbi, object.id, os);
74 CHECK_OP(os, recId);
75
76 UdrRecord record = dbi->getRecord(recId, os);
77 CHECK_OP(os, recId);
78
79 U2Object obj;
80 dbi->getRootDbi()->getObjectDbi()->getObject(obj, object.id, os);
81 CHECK_OP(os, recId);
82
83 object.visualName = obj.visualName;
84 object.version = obj.version;
85 CHECK_OP(os, recId);
86
87 object.serializer = record.getString(SERIALIZER, os);
88 CHECK_OP(os, recId);
89
90 return recId;
91 }
92
createObjectCore(UdrDbi * dbi,const QString & folder,U2RawData & object,U2OpStatus & os)93 UdrRecordId createObjectCore(UdrDbi *dbi, const QString &folder, U2RawData &object, U2OpStatus &os) {
94 dbi->createObject(RawDataUdrSchema::ID, object, folder, os);
95 CHECK_OP(os, UdrRecordId("", ""));
96
97 QList<UdrValue> data;
98 data << UdrValue(object.id);
99 data << UdrValue();
100 data << UdrValue(object.serializer);
101
102 return dbi->addRecord(RawDataUdrSchema::ID, data, os);
103 }
104 } // namespace
105
init(U2OpStatus & os)106 void RawDataUdrSchema::init(U2OpStatus &os) {
107 UdrSchema::FieldDesc content("content", UdrSchema::BLOB);
108 UdrSchema::FieldDesc serializer("serializer", UdrSchema::STRING);
109
110 QScopedPointer<UdrSchema> fileSchema(new UdrSchema(ID, true));
111 fileSchema->addField(content, os);
112 CHECK_OP(os, );
113 fileSchema->addField(serializer, os);
114 CHECK_OP(os, );
115
116 AppContext::getUdrSchemaRegistry()->registerSchema(fileSchema.data(), os);
117 if (!os.hasError()) {
118 fileSchema.take();
119 }
120 }
121
getObject(const U2EntityRef & objRef,U2OpStatus & os)122 U2RawData RawDataUdrSchema::getObject(const U2EntityRef &objRef, U2OpStatus &os) {
123 DbiHelper con(objRef.dbiRef, os);
124 CHECK_OP(os, U2RawData());
125
126 U2RawData result(objRef.dbiRef);
127 result.id = objRef.entityId;
128 retrieveObject(con.dbi, result, os);
129 return result;
130 }
131
createObject(const U2DbiRef & dbiRef,U2RawData & object,U2OpStatus & os)132 void RawDataUdrSchema::createObject(const U2DbiRef &dbiRef, U2RawData &object, U2OpStatus &os) {
133 createObject(dbiRef, U2ObjectDbi::ROOT_FOLDER, object, os);
134 }
135
createObject(const U2DbiRef & dbiRef,const QString & folder,U2RawData & object,U2OpStatus & os)136 void RawDataUdrSchema::createObject(const U2DbiRef &dbiRef, const QString &folder, U2RawData &object, U2OpStatus &os) {
137 DbiHelper con(dbiRef, os);
138 CHECK_OP(os, );
139
140 createObjectCore(con.dbi, folder, object, os);
141 }
142
writeContent(const QByteArray & data,const U2EntityRef & objRef,U2OpStatus & os)143 void RawDataUdrSchema::writeContent(const QByteArray &data, const U2EntityRef &objRef, U2OpStatus &os) {
144 DbiHelper con(objRef.dbiRef, os);
145 CHECK_OP(os, );
146
147 const UdrRecordId id = getRecordId(con.dbi, objRef.entityId, os);
148 CHECK_OP(os, );
149
150 QScopedPointer<OutputStream> oStream(con.dbi->createOutputStream(id, CONTENT, data.size(), os));
151 CHECK_OP(os, );
152 oStream->write(data.data(), data.size(), os);
153 }
154
writeContent(const U2DataId & masterId,const QByteArray & data,const U2EntityRef & objRef,U2OpStatus & os)155 void RawDataUdrSchema::writeContent(const U2DataId &masterId, const QByteArray &data, const U2EntityRef &objRef, U2OpStatus &os) {
156 DbiHelper con(objRef.dbiRef, os);
157 CHECK_OP(os, );
158 QScopedPointer<ModificationAction> updateAction(con.dbi->getModificationAction(masterId));
159 U2TrackModType trackMod = updateAction->prepare(os);
160 CHECK_OP(os, );
161
162 QByteArray modDetails;
163 if (trackMod == TrackOnUpdate) {
164 QByteArray olderData = readAllContent(objRef, os);
165 modDetails = U2DbiPackUtils::packUdr(olderData, data);
166 }
167
168 writeContent(data, objRef, os);
169
170 updateAction->addModification(objRef.entityId, U2ModType::udrUpdated, modDetails, os);
171 updateAction->complete(os);
172 }
173
readAllContent(const U2EntityRef & objRef,U2OpStatus & os)174 QByteArray RawDataUdrSchema::readAllContent(const U2EntityRef &objRef, U2OpStatus &os) {
175 DbiHelper con(objRef.dbiRef, os);
176 CHECK_OP(os, "");
177
178 const UdrRecordId id = getRecordId(con.dbi, objRef.entityId, os);
179 CHECK_OP(os, "");
180
181 QScopedPointer<InputStream> iStream(con.dbi->createInputStream(id, CONTENT, os));
182 CHECK_OP(os, "");
183
184 QByteArray result(iStream->available(), 0);
185 iStream->read(result.data(), iStream->available(), os);
186 CHECK_OP(os, "");
187
188 return result;
189 }
190
cloneObject(const U2EntityRef & srcObjRef,const U2DbiRef & dstDbiRef,const QString & dstFolder,U2RawData & dstObject,U2OpStatus & os)191 void RawDataUdrSchema::cloneObject(const U2EntityRef &srcObjRef, const U2DbiRef &dstDbiRef, const QString &dstFolder, U2RawData &dstObject, U2OpStatus &os) {
192 DbiOperationsBlock srcOpBlock(srcObjRef.dbiRef, os);
193 CHECK_OP(os, );
194 DbiOperationsBlock dstOpBlock(dstDbiRef, os);
195 CHECK_OP(os, );
196
197 // Prepare dbi connection
198 DbiHelper src(srcObjRef.dbiRef, os);
199 CHECK_OP(os, );
200 DbiHelper dst(dstDbiRef, os);
201 CHECK_OP(os, );
202
203 // Copy object
204 dstObject.dbiId = dstDbiRef.dbiId;
205 dstObject.id = srcObjRef.entityId;
206 const UdrRecordId srcId = retrieveObject(src.dbi, dstObject, os);
207 CHECK_OP(os, );
208 dstObject.version = 0;
209 const UdrRecordId dstId = createObjectCore(dst.dbi, dstFolder, dstObject, os);
210 CHECK_OP(os, );
211
212 // Copy content
213 QScopedPointer<InputStream> iStream(src.dbi->createInputStream(srcId, CONTENT, os));
214 CHECK_OP(os, );
215 QScopedPointer<OutputStream> oStream(dst.dbi->createOutputStream(dstId, CONTENT, iStream->available(), os));
216 CHECK_OP(os, );
217 QByteArray buffer(BUFFER_SIZE, 0);
218 char *bytes = buffer.data();
219 while (iStream->available() > 0) {
220 int read = iStream->read(bytes, BUFFER_SIZE, os);
221 CHECK_OP(os, );
222 oStream->write(bytes, read, os);
223 CHECK_OP(os, );
224 }
225 }
226
227 } // namespace U2
228