Project

General

Profile

1
package eu.dnetlib.functionality.modular.ui.workflows.controllers;
2

    
3
import java.io.IOException;
4
import java.io.StringReader;
5
import java.time.LocalDate;
6
import java.time.LocalDateTime;
7
import java.time.format.DateTimeFormatter;
8
import java.util.*;
9
import java.util.stream.Collectors;
10
import java.util.stream.StreamSupport;
11
import javax.annotation.Resource;
12
import javax.servlet.http.HttpServletResponse;
13

    
14
import com.google.common.base.Splitter;
15
import com.google.common.collect.Maps;
16
import com.google.common.collect.Sets;
17
import com.google.gson.Gson;
18
import com.google.gson.reflect.TypeToken;
19
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
20
import eu.dnetlib.functionality.modular.ui.AbstractAjaxController;
21
import eu.dnetlib.functionality.modular.ui.repositories.objects.RepoHIWorkflow;
22
import eu.dnetlib.functionality.modular.ui.repositories.objects.VocabularyEntry;
23
import eu.dnetlib.functionality.modular.ui.repositories.util.RepoUIUtils;
24
import eu.dnetlib.functionality.modular.ui.workflows.objects.*;
25
import eu.dnetlib.functionality.modular.ui.workflows.objects.sections.WorkflowSectionGrouper;
26
import eu.dnetlib.functionality.modular.ui.workflows.util.ISLookupClient;
27
import eu.dnetlib.functionality.modular.ui.workflows.util.ISRegistryClient;
28
import eu.dnetlib.miscutils.functional.xml.ApplyXsltDom4j;
29
import eu.dnetlib.msro.logging.DnetLogger;
30
import eu.dnetlib.msro.logging.LogMessage;
31
import eu.dnetlib.msro.notification.NotificationCondition;
32
import eu.dnetlib.msro.workflows.graph.Graph;
33
import eu.dnetlib.msro.workflows.graph.GraphLoader;
34
import eu.dnetlib.msro.workflows.graph.GraphNode;
35
import eu.dnetlib.msro.workflows.procs.ProcessRegistry;
36
import eu.dnetlib.msro.workflows.procs.WorkflowExecutor;
37
import eu.dnetlib.msro.workflows.procs.WorkflowProcess;
38
import eu.dnetlib.msro.workflows.procs.WorkflowProcess.StartMode;
39
import eu.dnetlib.msro.workflows.util.ProcessCallback;
40
import eu.dnetlib.msro.workflows.util.WorkflowsConstants;
41
import eu.dnetlib.rmi.data.ProtocolParameterType;
42
import eu.dnetlib.rmi.datasource.DatasourceManagerService;
43
import eu.dnetlib.rmi.datasource.DatasourceManagerServiceException;
44
import eu.dnetlib.rmi.enabling.ISLookUpException;
45
import eu.dnetlib.rmi.enabling.ISRegistryException;
46
import eu.dnetlib.rmi.manager.MSROException;
47
import org.apache.commons.io.IOUtils;
48
import org.apache.commons.lang3.StringUtils;
49
import org.apache.commons.lang3.math.NumberUtils;
50
import org.apache.commons.logging.Log;
51
import org.apache.commons.logging.LogFactory;
52
import org.dom4j.Document;
53
import org.dom4j.Element;
54
import org.dom4j.Node;
55
import org.dom4j.io.SAXReader;
56
import org.springframework.beans.factory.annotation.Autowired;
57
import org.springframework.beans.factory.annotation.Value;
58
import org.springframework.core.io.ClassPathResource;
59
import org.springframework.stereotype.Controller;
60
import org.springframework.web.bind.annotation.RequestMapping;
61
import org.springframework.web.bind.annotation.RequestParam;
62
import org.springframework.web.bind.annotation.ResponseBody;
63

    
64
// import com.google.common.collect.Lists;
65

    
66
/**
67
 * Web controller for the UI
68
 *
69
 * @author Michele Artini
70
 */
71

    
72
@Controller
73
public class WorkflowsController extends AbstractAjaxController {
74

    
75
	private static final Log log = LogFactory.getLog(WorkflowsController.class);
76

    
77
	@Autowired
78
	private ISLookupClient isLookupClient;
79

    
80
	@Autowired
81
	private ISRegistryClient isRegistryClient;
82

    
83
	@Autowired
84
	private RepoUIUtils repoUIUtils;
85

    
86
	@Autowired
87
	private GraphLoader graphLoader;
88

    
89
	@Autowired
90
	private ProcessRegistry graphProcessRegistry;
91

    
92
	@Autowired
93
	private WorkflowSectionGrouper workflowSectionGrouper;
94

    
95
	@Autowired
96
	private WorkflowExecutor workflowExecutor;
97

    
98
	@Resource(name = "msroWorkflowLogger")
99
	private DnetLogger dnetLogger;
100

    
101
	@Autowired
102
	private UniqueServiceLocator serviceLocator;
103

    
104
	@Value("${repo.ui.compatibilityLevels.vocabulary}")
105
	private String compatibilityLevelsVocabulary;
106

    
107
	@RequestMapping("/ui/wf/list_workflows.json")
108
	public @ResponseBody List<WorkflowItem> listWorflowsForSection(@RequestParam(value = "section", required = false) final String sectionName,
109
			@RequestParam(value = "dsId", required = false) final String dsId)
110
			throws ISLookUpException, IOException {
111
		if (sectionName != null) {
112
			return this.workflowSectionGrouper.listWorflowsForSection(sectionName);
113
		} else if (dsId != null) {
114
			return this.workflowSectionGrouper.listWorflowsForDatasource(dsId);
115
		} else {
116
			return new ArrayList<>();
117
		}
118
	}
119

    
120
	@RequestMapping("/ui/wf/workflow.html")
121
	public void getWorkflowHtml(final HttpServletResponse res, @RequestParam(value = "id", required = true) final String id) throws Exception {
122
		final SAXReader reader = new SAXReader();
123
		final String profile = this.isLookupClient.getProfile(id);
124
		final Document doc = reader.read(new StringReader(profile));
125
		final Element dsNode = (Element) doc.selectSingleNode("//DATASOURCE");
126
		if (dsNode != null) {
127
			final String dsId = dsNode.valueOf("@id");
128
			final String ifaceId = dsNode.valueOf("@interface");
129
			final String dsProfile = this.isLookupClient.getProfile(dsId);
130
			final Document doc2 = reader.read(new StringReader(dsProfile));
131
			dsNode.addAttribute("name", doc2.valueOf("//OFFICIAL_NAME"));
132
			dsNode.addAttribute("protocol", doc2.valueOf("//INTERFACE[@id = '" + ifaceId + "']/ACCESS_PROTOCOL"));
133
			final Node ifcNode = doc2.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
134
			final Element extraFields = dsNode.addElement("extraFields");
135
			for (final Object o : ifcNode.selectNodes("./INTERFACE_EXTRA_FIELD")) {
136
				final Element f = extraFields.addElement("field");
137
				f.addAttribute("name", ((Node) o).valueOf("@name"));
138
				f.setText(((Node) o).getText());
139
			}
140
		}
141

    
142
		final ApplyXsltDom4j xslt = new ApplyXsltDom4j(new ClassPathResource("/eu/dnetlib/functionality/modular/ui/workflows/xslt/wf_profile2html.xslt"));
143

    
144
		res.setContentType("text/html");
145
		IOUtils.copy(new StringReader(xslt.apply(doc)), res.getOutputStream());
146
	}
147

    
148
	@RequestMapping("/ui/wf/getGraph.do")
149
	public @ResponseBody GraphDetails getWorkflowGraphHtml(@RequestParam(value = "wfId", required = true) final String id) throws Exception {
150
		final String profile = this.isLookupClient.getProfile(id);
151
		final Document doc = new SAXReader().read(new StringReader(profile));
152

    
153
		final Graph graph = this.graphLoader.loadGraph(doc, new HashMap<>());
154

    
155
		return GraphDetails.from(graph);
156
	}
157

    
158
	@RequestMapping("/ui/wf/formProtocolParameters.find")
159
	public @ResponseBody List<Map<String, String>> getFormProtocolParameters(@RequestParam(value = "ds", required = true) final String repoId,
160
			@RequestParam(value = "iface", required = true) final String ifaceId)
161
			throws Exception {
162

    
163
		final String profile = this.isLookupClient.getRepoProfile(repoId);
164

    
165
		final SAXReader reader = new SAXReader();
166
		final Document doc = reader.read(new StringReader(profile));
167

    
168
		final Node ifcNode = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
169
		final String protocol = ifcNode.valueOf("./ACCESS_PROTOCOL");
170

    
171
		final List<Map<String, String>> list = new ArrayList<>();
172
		final Map<String, String> baseUrlParam = new HashMap<>();
173

    
174
		baseUrlParam.put("name", "baseUrl");
175
		baseUrlParam.put("type", ProtocolParameterType.TEXT.toString());
176
		baseUrlParam.put("value", ifcNode.valueOf("./BASE_URL"));
177
		baseUrlParam.put("regex", "^(http|https|ftp|ftps|sftp|file):\\/\\/");
178
		list.add(baseUrlParam);
179

    
180
		this.repoUIUtils.listParametersForProtocol(protocol).stream().map(pp -> {
181
			final Map<String, String> res = new HashMap<>();
182
			res.put("name", pp.getName());
183
			res.put("type", pp.getType().toString());
184
			res.put("value", ifcNode.valueOf("./ACCESS_PROTOCOL/@" + pp.getName()));
185

    
186
			if (StringUtils.isNotBlank(pp.getRegex())) {
187
				res.put("regex", pp.getRegex());
188
			}
189
			if (pp.isFunctionPopulated()) {
190
				res.put("functionPopulated", "true");
191
			}
192
			if (pp.isOptional()) {
193
				res.put("optional", "true");
194
			}
195

    
196
			return res;
197
		}).forEach(list::add);;
198

    
199
		return list;
200
	}
201

    
202
	@RequestMapping("/ui/wf/repoApi.html")
203
	public void getWorkflowHtml(final HttpServletResponse res,
204
			@RequestParam(value = "repoId", required = true) final String repoId,
205
			@RequestParam(value = "ifaceId", required = true) final String ifaceId) throws Exception {
206

    
207
		final String profile = this.isLookupClient.getRepoProfile(repoId);
208

    
209
		final SAXReader reader = new SAXReader();
210
		final Document doc = reader.read(new StringReader(profile));
211

    
212
		final Node ifcNode = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
213

    
214
		final String profileId = doc.valueOf("//RESOURCE_IDENTIFIER/@value");
215

    
216
		final String protocol = ifcNode.valueOf("./ACCESS_PROTOCOL");
217
		final Element extra = doc.getRootElement().addElement("extra_info");
218

    
219
		final Element compLevels = extra.addElement("compatibilityLevels");
220
		for (final VocabularyEntry e : this.repoUIUtils.fetchVocabularyTerms(this.compatibilityLevelsVocabulary)) {
221
			final Element l = compLevels.addElement("level");
222
			l.setText(e.getName());
223
		}
224

    
225
		final Element parameters = extra.addElement("parameters");
226
		for (final Object o : ifcNode.selectNodes("./ACCESS_PROTOCOL/@*")) {
227
			final Element p = parameters.addElement("param");
228
			p.addAttribute("name", ((Node) o).getName());
229
			p.setText(((Node) o).getText());
230
		}
231

    
232
		final Element extraFields = extra.addElement("extraFields");
233
		for (final Object o : ifcNode.selectNodes("./INTERFACE_EXTRA_FIELD")) {
234
			final Element f = extraFields.addElement("field");
235
			f.addAttribute("name", ((Node) o).valueOf("@name"));
236
			f.setText(((Node) o).getText());
237
		}
238

    
239
		final Element wfs = extra.addElement("workflows");
240
		for (final WorkflowItem item : this.isLookupClient.listWorflowsForApi(profileId, ifaceId)) {
241
			final Element wf = wfs.addElement("workflow");
242
			wf.addAttribute("id", item.getWfId());
243
			wf.addAttribute("name", item.getName());
244
			wf.addAttribute("description", item.getDesc());
245
			if (item.isDestroy()) {
246
				wf.addAttribute("destroy", "1");
247
			}
248
		}
249
		final Map<String, String> params = new HashMap<>();
250
		params.put("profileId", doc.valueOf("//RESOURCE_IDENTIFIER/@value"));
251
		params.put("ifaceId", ifaceId);
252
		params.put("protocol", protocol);
253
		params.put("baseUrl", ifcNode.valueOf("./BASE_URL"));
254
		params.put("prefix", doc.valueOf(".//FIELD[./key = 'NamespacePrefix']/value"));
255
		params.put("typology", ifcNode.valueOf("@typology"));
256
		params.put("compliance", ifcNode.valueOf("@compliance"));
257
		params.put("overrideCompliance", ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='overriding_compliance']"));
258

    
259
		doc.selectSingleNode("/RESOURCE_PROFILE/HEADER").detach();
260
		doc.selectSingleNode("/RESOURCE_PROFILE/BODY/CONFIGURATION/INTERFACES").detach();
261
		doc.selectSingleNode("/RESOURCE_PROFILE/BODY/CONFIGURATION/EXTRA_FIELDS").detach();
262
		doc.selectSingleNode("/RESOURCE_PROFILE/BODY/QOS").detach();
263
		doc.selectSingleNode("/RESOURCE_PROFILE/BODY/STATUS").detach();
264
		doc.selectSingleNode("/RESOURCE_PROFILE/BODY/SECURITY_PARAMETERS").detach();
265
		doc.selectSingleNode("/RESOURCE_PROFILE/BODY/BLACKBOARD").detach();
266

    
267
		final ApplyXsltDom4j xslt = new ApplyXsltDom4j(new ClassPathResource("/eu/dnetlib/functionality/modular/ui/workflows/xslt/repoApi.xslt"), params);
268

    
269
		res.setContentType("text/html");
270

    
271
		IOUtils.copy(new StringReader(xslt.apply(doc)), res.getOutputStream());
272
	}
273

    
274
	@RequestMapping("/ui/wf/wf.start")
275
	public @ResponseBody ProcessInfo startWorkflow(@RequestParam(value = "id", required = true) final String id) throws Exception {
276
		final String procId = this.workflowExecutor.startWorkflow(id, null);
277
		final WorkflowProcess process = this.graphProcessRegistry.findProcess(procId);
278
		return process != null ? new ProcessInfo(process) : new ProcessInfo(procId);
279
	}
280

    
281
	@RequestMapping("/ui/wf/wfTemplate.start")
282
	public @ResponseBody ProcessInfo startWorkflowTemplate(
283
			@RequestParam(value = "node", required = true) final String nodeName,
284
			@RequestParam(value = "parentWf", required = true) final String parentWf) throws Exception {
285

    
286
		final String profile = this.isLookupClient.getProfile(parentWf);
287
		final Document doc = (new SAXReader()).read(new StringReader(profile));
288
		final String family = doc.valueOf("//WORKFLOW_FAMILY");
289
		final int priority = NumberUtils.toInt(doc.valueOf("//WORKFLOW_PRIORITY"), WorkflowsConstants.DEFAULT_WF_PRIORITY);
290
		final String dsId = doc.valueOf("//DATASOURCE/@id");
291
		final String iface = doc.valueOf("//DATASOURCE/@interface");
292

    
293
		final Map<String, String> globalParams = new HashMap<String, String>();
294
		for (final Object o : doc.selectNodes("//CONFIGURATION/PARAMETERS/PARAM")) {
295
			final Element p = (Element) o;
296
			globalParams.put(p.valueOf("@name"), p.getTextTrim());
297
		}
298

    
299
		final Node node = doc.selectSingleNode("//NODE[@name='" + nodeName + "']");
300
		final Map<String, Object> params =
301
				GraphNode.newNode(nodeName, node.valueOf("@type"),
302
						this.graphLoader.calculateParamsForNode(node, globalParams))
303
						.resolveParamsWithNoEnv();
304

    
305
		if (!params.containsKey("wfTemplateId") || !(params.get("wfTemplateId") instanceof String)
306
				|| StringUtils.isBlank((String) params.get("wfTemplateId"))) {
307
			log.error("wfTemplateId is invalid or missing in profile " + parentWf);
308
			throw new MSROException("wfTemplateId is invalid or missing in profile " + parentWf);
309
		}
310

    
311
		if (params.containsKey("wfTemplateParams") && !(params.get("wfTemplateParams") instanceof Map)) {
312
			log.error("wfTemplateParams is invalid in profile " + parentWf);
313
			throw new MSROException("wfTemplateParams is invalid in profile " + parentWf);
314
		}
315

    
316
		final String wfTtemplateId = (String) params.get("wfTemplateId");
317
		@SuppressWarnings("unchecked")
318
		final Map<String, String> wfTtemplateParams =
319
				params.containsKey("wfTemplateParams") ? (Map<String, String>) params.get("wfTemplateParams") : new HashMap<>();
320

    
321
		final String procId = this.workflowExecutor.startWorkflowTemplate(wfTtemplateId, nodeName, family, priority, dsId, iface, wfTtemplateParams, null);
322

    
323
		final WorkflowProcess process = this.graphProcessRegistry.findProcess(procId);
324

    
325
		return process != null ? new ProcessInfo(process) : new ProcessInfo(procId);
326
	}
327

    
328
	@RequestMapping("/ui/wf/update_workflow.get")
329
	public @ResponseBody WorkflowUpdateInfo getWorkflowUpdateInfo(@RequestParam(value = "wfId", required = true) final String wfId) throws Exception {
330

    
331
		final String xml = this.isLookupClient.getProfile(wfId);
332

    
333
		final Document doc = (new SAXReader()).read(new StringReader(xml));
334

    
335
		final WorkflowUpdateInfo info = new WorkflowUpdateInfo();
336
		info.setWfId(wfId);
337
		info.setMode(StartMode.valueOf(doc.valueOf("//CONFIGURATION/@start")));
338
		info.setPriority(NumberUtils.toInt(doc.valueOf("//WORKFLOW_PRIORITY"), WorkflowsConstants.DEFAULT_WF_PRIORITY));
339

    
340
		info.setScheduled("true".equalsIgnoreCase(doc.valueOf("//SCHEDULING/@enabled")));
341
		info.setCron(doc.valueOf("//SCHEDULING/CRON"));
342
		info.setInterval(NumberUtils.toInt(doc.valueOf("//SCHEDULING/MININTERVAL"), 120)); // Default: 120 minutes
343

    
344
		for (final Object o : doc.selectNodes("//NOTIFICATIONS/EMAIL")) {
345
			info.getNotifications().add(new WorkflowNotificationInfo(
346
					((Element) o).valueOf("@address"),
347
					((Element) o).valueOf("@messageProfileId"),
348
					NotificationCondition.valueOf(((Element) o).valueOf("@condition"))));
349
		}
350

    
351
		return info;
352
	}
353

    
354
	@RequestMapping("/ui/wf/update_workflow.do")
355
	public @ResponseBody boolean updateWorkflow(@RequestParam(value = "json", required = true) final String json) throws Exception {
356

    
357
		final WorkflowUpdateInfo info = (new Gson()).fromJson(json, WorkflowUpdateInfo.class);
358

    
359
		log.info("Updating workflow " + info.getWfId());
360

    
361
		final String xml = this.isLookupClient.getProfile(info.getWfId());
362
		final boolean res = this.isRegistryClient.updateWorkflowProfile(info.getWfId(), xml, info);
363

    
364
		return res;
365
	}
366

    
367
	@RequestMapping("/ui/wf/proc.kill")
368
	public @ResponseBody boolean killProcessWorkflow(@RequestParam(value = "id", required = true) final String id) throws Exception {
369
		this.graphProcessRegistry.findProcess(id).kill();
370
		return true;
371
	}
372

    
373
	@RequestMapping("/ui/wf/journal.range")
374
	public @ResponseBody Collection<ProcessInfo> rangeWfJournal(@RequestParam(value = "start", required = true) final String start,
375
			@RequestParam(value = "end", required = true) final String end) throws Exception {
376

    
377
		final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
378
		final LocalDateTime startDate = LocalDate.parse(start, formatter).atTime(0, 0);
379
		final LocalDateTime endDate = LocalDate.parse(end, formatter).atTime(23, 59);
380

    
381
		final Iterator<Map<String, String>> iterator = this.dnetLogger.range(startDate, endDate);
382
		final LocalDateTime now = LocalDateTime.now();
383

    
384
		final Map<String, ProcessInfo> res = StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
385
				.map(this::toProcessInfo)
386
				.collect(Collectors.toMap(e -> e.getProcId(), e -> e, (e1, e2) -> e1));
387

    
388
		if (startDate.isBefore(now) && endDate.isAfter(now)) {
389
			for (final WorkflowProcess proc : this.graphProcessRegistry.listProcesses()) {
390
				res.put(proc.getId(), new ProcessInfo(proc));
391
			}
392
		}
393

    
394
		return res.values();
395
	}
396

    
397
	@RequestMapping("/ui/wf/journal.find")
398
	public @ResponseBody List<ProcessInfo> findWfJournal(@RequestParam(value = "wfs", required = true) final String wfs) {
399
		final Map<String, ProcessInfo> map = Maps.newHashMap();
400

    
401
		final Set<String> wfFilter = Sets.newHashSet(Splitter.on(",").omitEmptyStrings().trimResults().split(wfs));
402

    
403
		for (final String wfId : wfFilter) {
404
			final Iterator<Map<String, String>> iterator = this.dnetLogger.find(WorkflowsConstants.LOG_WF_PROFILE_ID, wfId);
405
			StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
406
					.map(this::toProcessInfo)
407
					.forEach(e -> map.put(e.getProcId(), e));
408
		}
409

    
410
		for (final WorkflowProcess proc : this.graphProcessRegistry.listProcesses()) {
411
			if (wfFilter.contains(proc.getProfileId())) {
412
				map.put(proc.getProfileId(), new ProcessInfo(proc));
413
			}
414
		}
415

    
416
		return map.values().stream().sorted(new Comparator<ProcessInfo>() {
417

    
418
			@Override
419
			public int compare(final ProcessInfo p1, final ProcessInfo p2) {
420
				if (p1.getDate() == 0) {
421
					return -1;
422
				} else if (p2.getDate() == 0) {
423
					return 1;
424
				} else {
425
					return Long.compare(p2.getDate(), p1.getDate());
426
				}
427
			}
428
		}).collect(Collectors.toList());
429
	}
430

    
431
	@RequestMapping("/ui/wf/journal_byFamily.find")
432
	public @ResponseBody Collection<ProcessInfo> findWfJournalByFamily(@RequestParam(value = "family", required = true) final String family)
433
			throws IOException {
434

    
435
		final Iterator<Map<String, String>> iterator = this.dnetLogger.find(WorkflowsConstants.LOG_WF_FAMILY, family);
436

    
437
		return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
438
				.map(this::toProcessInfo)
439
				.collect(Collectors.toList());
440

    
441
	}
442

    
443
	@RequestMapping("/ui/wf/journal.get")
444
	public @ResponseBody ProcessInfo getWfJournalLog(@RequestParam(value = "id", required = true) final String procId) throws Exception {
445
		final WorkflowProcess process = this.graphProcessRegistry.findProcess(procId);
446
		final Map<String, String> logs = this.dnetLogger.findOne("system:processId", procId);
447

    
448
		final ProcessInfo info = (process != null) ? new ProcessInfo(process) : new ProcessInfo(logs);
449

    
450
		if (logs != null && !logs.isEmpty()) {
451
			logs.keySet().stream().sorted().forEach(k -> info.getOutputParams().add(new EnvParam(k, logs.get(k))));
452
		}
453

    
454
		return info;
455
	}
456

    
457
	@RequestMapping(value = "/ui/wf/saveParams.do")
458
	public @ResponseBody boolean saveWorkflowParams(@RequestParam(value = "wf", required = true) final String wfId,
459
			@RequestParam(value = "params", required = true) final String jsonParams) throws Exception {
460

    
461
		final String xml = this.isLookupClient.getProfile(wfId);
462

    
463
		final Map<String, String> params = new Gson().fromJson(jsonParams, new TypeToken<Map<String, String>>() {}.getType());
464

    
465
		return this.isRegistryClient.updateWorkflowProfile(wfId, xml, params);
466
	}
467

    
468
	@RequestMapping(value = "/ui/wf/obtainSubWorkflows.do")
469
	public @ResponseBody List<Map<String, String>> obtainSubWorkflows(@RequestParam(value = "id", required = true) final String wfId) {
470
		return this.isLookupClient.obtainSubWorkflows(wfId);
471
	}
472

    
473
	@RequestMapping(value = "/ui/wf/repohi_wfs.find")
474
	public @ResponseBody List<RepoHIWorkflow> listRepoHIWorkflows(@RequestParam(value = "compliance", required = true) final String compliance,
475
			@RequestParam(value = "type", required = true) final String type) throws ISLookUpException {
476

    
477
		return this.isLookupClient.listRepoHiWorkflows(compliance, type);
478
	}
479

    
480
	@RequestMapping("/ui/wf/repohi.start")
481
	public @ResponseBody List<String> newRepoWorkflow(@RequestParam(value = "id", required = true) final String repoId,
482
			@RequestParam(value = "iface", required = true) final String ifaceId,
483
			@RequestParam(value = "wf", required = true) final String wfId) throws Exception {
484

    
485
		final String procId = this.workflowExecutor.startRepoHiWorkflow(wfId, repoId, ifaceId, new ProcessCallback() {
486

    
487
			@Override
488
			public void onSuccess() {
489
				try {
490
					WorkflowsController.this.serviceLocator.getService(DatasourceManagerService.class).updateActivationStatus(repoId, ifaceId, true);
491
				} catch (final DatasourceManagerServiceException e) {
492
					log.error("Error updating activation status of " + repoId, e);
493
				}
494
			}
495

    
496
			@Override
497
			public void onFail() {}
498
		});
499

    
500
		return Arrays.asList(procId);
501
	}
502

    
503
	@RequestMapping("/ui/wf/repobye.start")
504
	public @ResponseBody List<String> destroyRepoWorkflow(@RequestParam(value = "wf", required = true) final String wf)
505
			throws Exception {
506

    
507
		final String profile = this.isLookupClient.getProfile(wf);
508
		final Document doc = (new SAXReader()).read(new StringReader(profile));
509
		final String dsId = doc.valueOf("//DATASOURCE/@id");
510
		final String iface = doc.valueOf("//DATASOURCE/@interface");
511

    
512
		final Map<String, String> globalParams = new HashMap<String, String>();
513
		for (final Object o : doc.selectNodes("//CONFIGURATION/PARAMETERS/PARAM")) {
514
			final Element p = (Element) o;
515
			globalParams.put(p.valueOf("@name"), p.getTextTrim());
516
		}
517

    
518
		final Node node = doc.selectSingleNode("//DESTROY_WORKFLOW_TEMPLATE");
519
		if (node == null) {
520
			log.error("DESTROY WF is invalid or missing in profile " + wf);
521
			throw new MSROException("DESTROY WF is invalid or missing in profile " + wf);
522
		}
523

    
524
		final String wfTtemplateId = node.valueOf("@id");
525

    
526
		final Map<String, String> params = GraphNode.newNode("REPO_BYE", "REPO_BYE",
527
				this.graphLoader.calculateParamsForNode(node, globalParams))
528
				.resolveParamsWithNoEnv().entrySet()
529
				.stream()
530
				.filter(e -> e.getValue() instanceof String)
531
				.collect(Collectors.toMap(e -> e.getKey(), e -> (String) e.getValue(), (e1, e2) -> e1));
532

    
533
		final String procId =
534
				this.workflowExecutor.startWorkflowTemplate(wfTtemplateId, "REPO_BYE", "REPO_BYE", WorkflowsConstants.DEFAULT_WF_PRIORITY, dsId, iface,
535
						params, new ProcessCallback() {
536

    
537
							@Override
538
							public void onSuccess() {
539
								try {
540
									WorkflowsController.this.isRegistryClient.deleteProfile(wf);
541
								} catch (final ISRegistryException e) {
542
									log.error("Error deleting workflow: " + wf);
543
								}
544
							}
545

    
546
							@Override
547
							public void onFail() {}
548
						});
549

    
550
		return Arrays.asList(procId);
551
	}
552

    
553
	private ProcessInfo toProcessInfo(final Map<String, String> input) {
554
		final ProcessInfo info = new ProcessInfo();
555

    
556
		info.setProcId(input.get(WorkflowsConstants.LOG_WF_PROCESS_ID));
557
		info.setWfId(input.get(WorkflowsConstants.LOG_WF_PROFILE_ID));
558
		info.setName(input.get(WorkflowsConstants.LOG_WF_NAME));
559
		info.setFamily(input.get(WorkflowsConstants.LOG_WF_FAMILY));
560
		info.setDatasource(input.containsKey(WorkflowsConstants.LOG_DATASOURCE_NAME) ? input.get(WorkflowsConstants.LOG_DATASOURCE_NAME) : "");
561
		info.setStatus(input.get(WorkflowsConstants.LOG_WF_PROCESS_STATUS));
562
		info.setDate(NumberUtils.toLong(input.get(LogMessage.LOG_DATE_FIELD), 0));
563
		info.setStartDate(info.getStartDate());
564
		info.setEndDate(info.getEndDate());
565

    
566
		return info;
567

    
568
	}
569

    
570
}
(4-4/4)