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 "IntegralBusUtils.h"
23 
24 #include <U2Core/U2OpStatusUtils.h>
25 #include <U2Core/U2SafePoints.h>
26 
27 #include <U2Lang/BaseSlots.h>
28 #include <U2Lang/BaseTypes.h>
29 #include <U2Lang/IntegralBus.h>
30 #include <U2Lang/IntegralBusModel.h>
31 
32 namespace U2 {
33 namespace Workflow {
34 
splitCandidates(const QList<Descriptor> & candidates,const Descriptor & toDesc,DataTypePtr toDatatype)35 IntegralBusUtils::SplitResult IntegralBusUtils::splitCandidates(const QList<Descriptor> &candidates, const Descriptor &toDesc, DataTypePtr toDatatype) {
36     CandidatesSplitter *splitter = CandidatesSplitterRegistry::instance()->findSplitter(toDesc, toDatatype);
37     SAFE_POINT(nullptr != splitter, "NULL splitter", SplitResult());
38     return splitter->splitCandidates(candidates);
39 }
40 
remapBus(StrStrMap & busMap,const ActorId & oldId,const ActorId & newId,const PortMapping & mapping)41 void IntegralBusUtils::remapBus(StrStrMap &busMap, const ActorId &oldId, const ActorId &newId, const PortMapping &mapping) {
42     foreach (QString key, busMap.uniqueKeys()) {
43         U2OpStatus2Log os;
44         QList<IntegralBusSlot> slotList = IntegralBusSlot::listFromString(busMap[key], os);
45         QList<IntegralBusSlot> newSlots;
46         for (const IntegralBusSlot &slot : qAsConst(slotList)) {
47             IntegralBusSlot newSlot = slot;
48             if (slot.actorId() == oldId) {
49                 U2OpStatusImpl os2;
50                 QString newSlotId = mapping.getDstSlotId(slot.getId(), os2);
51                 if (!os2.hasError()) {
52                     newSlot = IntegralBusSlot(newSlotId, "", newId);
53                 }
54             }
55             newSlots << newSlot;
56         }
57         busMap[key] = IntegralBusSlot::listToString(newSlots);
58     }
59 }
60 
remapPathedSlotString(QString & pathedSlotStr,const ActorId & oldId,const ActorId & newId,const PortMapping & mapping)61 void IntegralBusUtils::remapPathedSlotString(QString &pathedSlotStr, const ActorId &oldId, const ActorId &newId, const PortMapping &mapping) {
62     if (pathedSlotStr.isEmpty()) {
63         return;
64     }
65     QString slotStr;
66     QStringList path;
67     BusMap::parseSource(pathedSlotStr, slotStr, path);
68 
69     U2OpStatus2Log logOs;
70     IntegralBusSlot slot = IntegralBusSlot::fromString(slotStr, logOs);
71     if (slot.actorId() == oldId) {
72         U2OpStatusImpl os;
73         QString newSlot = mapping.getDstSlotId(slot.getId(), os);
74         if (!os.hasError()) {
75             slot = IntegralBusSlot(newSlot, "", newId);
76         }
77     }
78     pathedSlotStr = slot.toString();
79 
80     if (!path.isEmpty()) {
81         for (QStringList::iterator i = path.begin(); i != path.end(); i++) {
82             if (*i == oldId) {
83                 *i = newId;
84             }
85         }
86         pathedSlotStr += ">" + path.join(",");
87     }
88 }
89 
90 namespace {
91 enum StringSlotType {
92     TEXT,
93     URL,
94     DATASET
95 };
96 
isUrlSlot(const Descriptor & slot)97 bool isUrlSlot(const Descriptor &slot) {
98     const QString id = slot.getId();
99     return id.contains(BaseSlots::URL_SLOT().getId());
100 }
isDatasetSlot(const Descriptor & slot)101 bool isDatasetSlot(const Descriptor &slot) {
102     return (BaseSlots::DATASET_SLOT() == slot);
103 }
104 
getSlotType(const Descriptor & slot)105 StringSlotType getSlotType(const Descriptor &slot) {
106     if (isUrlSlot(slot)) {
107         return URL;
108     }
109     if (isDatasetSlot(slot)) {
110         return DATASET;
111     }
112     return TEXT;
113 }
114 }  // namespace
115 
getSlotsByType(const QMap<Descriptor,DataTypePtr> & busMap,const Descriptor & slot,const DataTypePtr & type)116 QList<Descriptor> IntegralBusUtils::getSlotsByType(const QMap<Descriptor, DataTypePtr> &busMap, const Descriptor &slot, const DataTypePtr &type) {
117     QList<Descriptor> result = busMap.keys(type);
118     CHECK(BaseTypes::STRING_TYPE() == type, result);
119     CHECK(result.size() > 1, result);
120 
121     const StringSlotType targetType = getSlotType(slot);
122     foreach (const Descriptor &desc, result) {
123         if (targetType != getSlotType(desc)) {
124             result.removeOne(desc);
125         }
126     }
127     return result;
128 }
129 
130 /************************************************************************/
131 /* Splitters */
132 /************************************************************************/
133 class DefaultSplitter : public CandidatesSplitter {
134 public:
DefaultSplitter()135     DefaultSplitter()
136         : CandidatesSplitter(ID) {
137     }
138 
canSplit(const Descriptor &,DataTypePtr)139     bool canSplit(const Descriptor & /*toDesc*/, DataTypePtr /*toDatatype*/) {
140         return true;
141     }
142 
143     static const QString ID;
144 
145 protected:
isMain(const QString &)146     bool isMain(const QString & /*candidateSlotId*/) {
147         return true;
148     }
149 };
150 
151 const QString DefaultSplitter::ID = "default";
152 
153 class TextSplitter : public CandidatesSplitter {
154 public:
TextSplitter()155     TextSplitter()
156         : CandidatesSplitter(ID) {
157     }
158 
canSplit(const Descriptor &,DataTypePtr toDatatype)159     bool canSplit(const Descriptor & /*toDesc*/, DataTypePtr toDatatype) {
160         return (BaseTypes::STRING_TYPE() == toDatatype);
161     }
162 
163     static const QString ID;
164 
165 protected:
isMain(const QString & candidateSlotId)166     bool isMain(const QString &candidateSlotId) {
167         return (BaseSlots::URL_SLOT().getId() != candidateSlotId && BaseSlots::DATASET_SLOT().getId() != candidateSlotId);
168     }
169 };
170 const QString TextSplitter::ID = "text";
171 
172 class DatasetsSplitter : public CandidatesSplitter {
173 public:
DatasetsSplitter()174     DatasetsSplitter()
175         : CandidatesSplitter(ID) {
176     }
177 
canSplit(const Descriptor & toDesc,DataTypePtr toDatatype)178     bool canSplit(const Descriptor &toDesc, DataTypePtr toDatatype) {
179         return ((BaseTypes::STRING_TYPE() == toDatatype) && isDatasetSlot(toDesc));
180     }
181 
182     static const QString ID;
183 
184 protected:
isMain(const QString & candidateSlotId)185     bool isMain(const QString &candidateSlotId) {
186         return (BaseSlots::DATASET_SLOT().getId() == candidateSlotId);
187     }
188 };
189 
190 const QString DatasetsSplitter::ID = "datasets";
191 
192 class UrlSplitter : public CandidatesSplitter {
193 public:
UrlSplitter()194     UrlSplitter()
195         : CandidatesSplitter(ID) {
196     }
197 
canSplit(const Descriptor & toDesc,DataTypePtr toDatatype)198     bool canSplit(const Descriptor &toDesc, DataTypePtr toDatatype) {
199         return ((BaseTypes::STRING_TYPE() == toDatatype) && isUrlSlot(toDesc));
200     }
201 
202     static const QString ID;
203 
204 protected:
isMain(const QString & candidateSlotId)205     bool isMain(const QString &candidateSlotId) {
206         return (BaseSlots::URL_SLOT().getId() == candidateSlotId);
207     }
208 };
209 
210 const QString UrlSplitter::ID = "url";
211 
212 /************************************************************************/
213 /* CandidatesSplitter */
214 /************************************************************************/
CandidatesSplitter(const QString & _id)215 CandidatesSplitter::CandidatesSplitter(const QString &_id)
216     : id(_id) {
217 }
218 
~CandidatesSplitter()219 CandidatesSplitter::~CandidatesSplitter() {
220 }
221 
splitCandidates(const QList<Descriptor> & candidates)222 IntegralBusUtils::SplitResult CandidatesSplitter::splitCandidates(const QList<Descriptor> &candidates) {
223     IntegralBusUtils::SplitResult r;
224     foreach (const Descriptor &c, candidates) {
225         U2OpStatus2Log os;
226         IntegralBusSlot slot = IntegralBusSlot::fromString(c.getId(), os);
227         if (slot.getId().isEmpty() || isMain(slot.getId())) {
228             r.mainDescs << c;
229         } else {
230             r.otherDescs << c;
231         }
232     }
233     return r;
234 }
235 
getId() const236 const QString &CandidatesSplitter::getId() const {
237     return id;
238 }
239 
240 /************************************************************************/
241 /* CandidatesSplitterRegistry */
242 /************************************************************************/
243 CandidatesSplitterRegistry *CandidatesSplitterRegistry::_instance = nullptr;
instance()244 CandidatesSplitterRegistry *CandidatesSplitterRegistry::instance() {
245     if (nullptr == _instance) {
246         _instance = new CandidatesSplitterRegistry();
247     }
248     return _instance;
249 }
250 
findSplitter(const Descriptor & toDesc,DataTypePtr toDatatype)251 CandidatesSplitter *CandidatesSplitterRegistry::findSplitter(const Descriptor &toDesc, DataTypePtr toDatatype) {
252     foreach (CandidatesSplitter *splitter, splitters) {
253         if (splitter->canSplit(toDesc, toDatatype)) {
254             return splitter;
255         }
256     }
257     return nullptr;
258 }
259 
findSplitter(const QString & id)260 CandidatesSplitter *CandidatesSplitterRegistry::findSplitter(const QString &id) {
261     foreach (CandidatesSplitter *splitter, splitters) {
262         if (id == splitter->getId()) {
263             return splitter;
264         }
265     }
266     return nullptr;
267 }
268 
registerSplitter(CandidatesSplitter * splitter)269 void CandidatesSplitterRegistry::registerSplitter(CandidatesSplitter *splitter) {
270     if (!splitters.contains(splitter)) {
271         splitters.prepend(splitter);
272     }
273 }
274 
unregisterSplitter(const QString & id)275 void CandidatesSplitterRegistry::unregisterSplitter(const QString &id) {
276     CandidatesSplitter *splitter = findSplitter(id);
277     CHECK(nullptr != splitter, );
278     splitters.removeAll(splitter);
279     delete splitter;
280 }
281 
CandidatesSplitterRegistry()282 CandidatesSplitterRegistry::CandidatesSplitterRegistry() {
283     // The order is needed
284     splitters << new UrlSplitter();
285     splitters << new DatasetsSplitter();
286     splitters << new TextSplitter();
287     splitters << new DefaultSplitter();
288 }
289 
~CandidatesSplitterRegistry()290 CandidatesSplitterRegistry::~CandidatesSplitterRegistry() {
291     qDeleteAll(splitters);
292     splitters.clear();
293 }
294 
295 }  // namespace Workflow
296 }  // namespace U2
297