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