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 "WorkflowDebugMessageParserImpl.h"
23 
24 #include <QScopedPointer>
25 #include <QStringList>
26 #include <QVariantMap>
27 
28 #include <U2Core/AnnotationTableObject.h>
29 #include <U2Core/AppContext.h>
30 #include <U2Core/AppSettings.h>
31 #include <U2Core/TextObject.h>
32 #include <U2Core/U2OpStatusUtils.h>
33 #include <U2Core/U2SafePoints.h>
34 #include <U2Core/UserApplicationsSettings.h>
35 
36 #include <U2Gui/ExportObjectUtils.h>
37 
38 #include <U2Lang/BaseSlots.h>
39 #include <U2Lang/WorkflowContext.h>
40 #include <U2Lang/WorkflowTransport.h>
41 
42 #include "AnnotationsMessageTranslator.h"
43 #include "AssemblyMessageTranslator.h"
44 #include "BaseMessageTranslator.h"
45 #include "MultipleAlignmentMessageTranslator.h"
46 #include "SequenceMessageTranslator.h"
47 #include "VariationTrackMessageTranslator.h"
48 
49 const QString PRODUCING_ACTOR_AND_DATA_TYPE_SEPARATOR = ":";
50 const QString FILE_NAME_WORDS_SEPARATOR = "_";
51 const QString INVESTIGATION_FILES_DIR_NAME = "investigation_files";
52 
53 namespace U2 {
54 
55 using namespace Workflow;
56 
initParsedInfo()57 void WorkflowDebugMessageParserImpl::initParsedInfo() {
58     if (Q_LIKELY(!messageTypes.isEmpty())) {
59         foreach (const QString &typeName, messageTypes) {
60             parsedInfo[typeName] = QQueue<QString>();
61         }
62     }
63 }
64 
convertToString(const QString & contentIdentifier,const QVariant & content) const65 QString WorkflowDebugMessageParserImpl::convertToString(const QString &contentIdentifier,
66                                                         const QVariant &content) const {
67     QScopedPointer<BaseMessageTranslator> messageTranslator(createMessageTranslator(
68         getMessageTypeFromIdentifier(contentIdentifier), content));
69     SAFE_POINT(!messageTranslator.isNull(), "Invalid message translator detected!", QString());
70     const QString result = messageTranslator->getTranslation();
71     return result;
72 }
73 
getMessageTypeFromIdentifier(const QString & messageIdentifier) const74 QString WorkflowDebugMessageParserImpl::getMessageTypeFromIdentifier(
75     const QString &messageIdentifier) const {
76     return messageIdentifier.right(messageIdentifier.size() - messageIdentifier.lastIndexOf(PRODUCING_ACTOR_AND_DATA_TYPE_SEPARATOR) - 1);
77 }
78 
getAllMessageValues()79 WorkflowInvestigationData WorkflowDebugMessageParserImpl::getAllMessageValues() {
80     if (!sourceMessages.isEmpty()) {
81         foreach (const QString &key, sourceMessages.head().keys()) {
82             const QString messageType = getMessageTypeFromIdentifier(key);
83             if (Q_UNLIKELY(!possibleMessageTypes.contains(messageType))) {
84                 coreLog.info(QObject::tr("Messages in requested queue include info of the '%1' "
85                                          "data type that is currently unsupported for view. "
86                                          "No intermediate data will be displayed")
87                                  .arg(messageType));
88                 return parsedInfo;
89             }
90             if (Q_UNLIKELY(!messageTypes.contains(key))) {
91                 messageTypes << key;
92             }
93         }
94         initParsedInfo();
95         foreach (const QVariantMap &messageContent, sourceMessages) {
96             foreach (const QString &key, messageContent.keys()) {
97                 SAFE_POINT(messageTypes.contains(key), "Unexpected message type encountered!", parsedInfo);
98                 parsedInfo[key].enqueue(convertToString(key, messageContent[key]));
99             }
100         }
101     }
102     return parsedInfo;
103 }
104 
convertMessagesToDocuments(const QString & convertedType,const QString & schemeName,quint32 messageNumber)105 void WorkflowDebugMessageParserImpl::convertMessagesToDocuments(const QString &convertedType, const QString &schemeName, quint32 messageNumber) {
106     SAFE_POINT(!convertedType.isEmpty(), "Invalid message type detected!", );
107     const AppSettings *appSettings = AppContext::getAppSettings();
108     SAFE_POINT(nullptr != appSettings, "Invalid application settings' storage!", );
109     const UserAppsSettings *userSettings = appSettings->getUserAppsSettings();
110     SAFE_POINT(nullptr != userSettings, "Invalid user application settings' storage!", );
111     QString tmpFolderUrl = (userSettings->getCurrentProcessTemporaryDirPath());
112     tmpFolderUrl.replace("//", "/");
113 
114     quint32 messageCounter = ++messageNumber;
115     foreach (const QVariantMap &mapData, sourceMessages) {
116         SAFE_POINT(mapData.keys().contains(convertedType), "Invalid message type detected!", );
117         const QString messageType = getMessageTypeFromIdentifier(convertedType);
118         const QString baseFileUrl = tmpFolderUrl + "/" + schemeName + FILE_NAME_WORDS_SEPARATOR + messageType + FILE_NAME_WORDS_SEPARATOR + "m" + QString::number(messageCounter);
119         if (BaseSlots::ANNOTATION_TABLE_SLOT().getId() == messageType) {
120             const QVariant annotationsData = mapData[convertedType];
121             const QList<SharedAnnotationData> annList = StorageUtils::getAnnotationTable(context->getDataStorage(), annotationsData);
122 
123             AnnotationTableObject *annsObj = new AnnotationTableObject("Annotations", context->getDataStorage()->getDbiRef());
124             annsObj->addAnnotations(annList);
125 
126             ExportObjectUtils::exportAnnotations(annsObj, baseFileUrl);
127         } else {
128             GObject *objectToWrite = fetchObjectFromMessage(messageType, mapData[convertedType]);
129             if (Q_LIKELY(nullptr != objectToWrite)) {
130                 ExportObjectUtils::exportObject2Document(objectToWrite, baseFileUrl, false);
131                 ++messageCounter;
132             }
133         }
134     }
135 }
136 
createMessageTranslator(const QString & messageType,const QVariant & messageData) const137 BaseMessageTranslator *WorkflowDebugMessageParserImpl::createMessageTranslator(const QString &messageType, const QVariant &messageData) const {
138     BaseMessageTranslator *result = nullptr;
139     if (BaseSlots::DNA_SEQUENCE_SLOT().getId() == messageType) {
140         result = new SequenceMessageTranslator(messageData, context);
141     } else if (BaseSlots::ANNOTATION_TABLE_SLOT().getId() == messageType) {
142         result = new AnnotationsMessageTranslator(messageData, context);
143     } else if (BaseSlots::MULTIPLE_ALIGNMENT_SLOT().getId() == messageType) {
144         result = new MultipleAlignmentMessageTranslator(messageData, context);
145     } else if (BaseSlots::ASSEMBLY_SLOT().getId() == messageType) {
146         result = new AssemblyMessageTranslator(messageData, context);
147     } else if (BaseSlots::VARIATION_TRACK_SLOT().getId() == messageType) {
148         result = new VariationTrackMessageTranslator(messageData, context);
149     } else if (BaseSlots::TEXT_SLOT().getId() == messageType || BaseSlots::URL_SLOT().getId() == messageType || BaseSlots::DATASET_SLOT().getId() == messageType || BaseSlots::FASTA_HEADER_SLOT().getId() == messageType) {
150         result = new BaseMessageTranslator(messageData, context);
151     } else {
152         FAIL("Unable to determine message type", result);
153     }
154     return result;
155 }
156 
fetchObjectFromMessage(const QString & messageType,const QVariant & messageData) const157 GObject *WorkflowDebugMessageParserImpl::fetchObjectFromMessage(const QString &messageType, const QVariant &messageData) const {
158     GObject *result = nullptr;
159     if (BaseSlots::TEXT_SLOT().getId() == messageType) {
160         SAFE_POINT(messageData.canConvert<QString>(), "Supplied message doesn't contain text data", nullptr);
161         const QString documentText = messageData.value<QString>();
162         U2OpStatus2Log os;
163         result = TextObject::createInstance(documentText, "wd_investigation_tmp_text_object", context->getDataStorage()->getDbiRef(), os);
164         return result;
165     } else if (BaseSlots::URL_SLOT().getId() == messageType || BaseSlots::DATASET_SLOT().getId() == messageType || BaseSlots::FASTA_HEADER_SLOT().getId() == messageType || BaseSlots::ANNOTATION_TABLE_SLOT().getId() == messageType) {
166         return result;
167     }
168     SAFE_POINT(messageData.canConvert<SharedDbiDataHandler>(),
169                "Supplied message doesn't contain DB reference",
170                nullptr);
171     SharedDbiDataHandler objectId = messageData.value<SharedDbiDataHandler>();
172 
173     if (BaseSlots::DNA_SEQUENCE_SLOT().getId() == messageType) {
174         result = StorageUtils::getSequenceObject(context->getDataStorage(), objectId);
175     } else if (BaseSlots::MULTIPLE_ALIGNMENT_SLOT().getId() == messageType) {
176         result = StorageUtils::getMsaObject(context->getDataStorage(), objectId);
177     } else if (BaseSlots::ASSEMBLY_SLOT().getId() == messageType) {
178         result = StorageUtils::getAssemblyObject(context->getDataStorage(), objectId);
179     } else if (BaseSlots::VARIATION_TRACK_SLOT().getId() == messageType) {
180         result = StorageUtils::getVariantTrackObject(context->getDataStorage(), objectId);
181     }
182     SAFE_POINT(nullptr != result, "Could not obtain object from dbi", nullptr);
183     return result;
184 }
185 
186 }  // namespace U2
187