Project

General

Profile

1 26600 sandro.lab
package eu.dnetlib.functionality.modular.ui.workflows.controllers;
2
3
import java.io.IOException;
4 39743 michele.ar
import java.io.StringReader;
5 41872 sandro.lab
import java.time.LocalDate;
6 41838 michele.ar
import java.time.LocalDateTime;
7
import java.time.format.DateTimeFormatter;
8 43444 sandro.lab
import java.util.*;
9 42174 michele.ar
import java.util.stream.Collectors;
10
import java.util.stream.StreamSupport;
11 26600 sandro.lab
import javax.annotation.Resource;
12
import javax.servlet.http.HttpServletResponse;
13
14 39848 michele.ar
import com.google.common.base.Splitter;
15 26600 sandro.lab
import com.google.common.collect.Maps;
16 39848 michele.ar
import com.google.common.collect.Sets;
17 26600 sandro.lab
import com.google.gson.Gson;
18 29892 michele.ar
import com.google.gson.reflect.TypeToken;
19 42174 michele.ar
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
20 30058 michele.ar
import eu.dnetlib.functionality.modular.ui.AbstractAjaxController;
21 41423 michele.ar
import eu.dnetlib.functionality.modular.ui.repositories.objects.RepoHIWorkflow;
22 41339 michele.ar
import eu.dnetlib.functionality.modular.ui.repositories.objects.VocabularyEntry;
23
import eu.dnetlib.functionality.modular.ui.repositories.util.RepoUIUtils;
24 43444 sandro.lab
import eu.dnetlib.functionality.modular.ui.workflows.objects.*;
25 26600 sandro.lab
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 41339 michele.ar
import eu.dnetlib.miscutils.functional.xml.ApplyXsltDom4j;
29 41838 michele.ar
import eu.dnetlib.msro.logging.DnetLogger;
30
import eu.dnetlib.msro.logging.LogMessage;
31 42284 michele.ar
import eu.dnetlib.msro.notification.NotificationCondition;
32 42288 michele.ar
import eu.dnetlib.msro.workflows.graph.Graph;
33 42069 michele.ar
import eu.dnetlib.msro.workflows.graph.GraphLoader;
34 43063 michele.ar
import eu.dnetlib.msro.workflows.graph.GraphNode;
35 40096 michele.ar
import eu.dnetlib.msro.workflows.procs.ProcessRegistry;
36 40099 michele.ar
import eu.dnetlib.msro.workflows.procs.WorkflowExecutor;
37 40096 michele.ar
import eu.dnetlib.msro.workflows.procs.WorkflowProcess;
38 42284 michele.ar
import eu.dnetlib.msro.workflows.procs.WorkflowProcess.StartMode;
39 42174 michele.ar
import eu.dnetlib.msro.workflows.util.ProcessCallback;
40 26600 sandro.lab
import eu.dnetlib.msro.workflows.util.WorkflowsConstants;
41 42122 michele.ar
import eu.dnetlib.rmi.data.ProtocolParameterType;
42 42174 michele.ar
import eu.dnetlib.rmi.datasource.DatasourceManagerService;
43
import eu.dnetlib.rmi.datasource.DatasourceManagerServiceException;
44 41838 michele.ar
import eu.dnetlib.rmi.enabling.ISLookUpException;
45 42174 michele.ar
import eu.dnetlib.rmi.enabling.ISRegistryException;
46 42069 michele.ar
import eu.dnetlib.rmi.manager.MSROException;
47 43444 sandro.lab
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 26600 sandro.lab
64 42621 sandro.lab
// import com.google.common.collect.Lists;
65
66 26600 sandro.lab
/**
67
 * Web controller for the UI
68 39624 michele.ar
 *
69 26600 sandro.lab
 * @author Michele Artini
70
 */
71
72
@Controller
73 30058 michele.ar
public class WorkflowsController extends AbstractAjaxController {
74 26600 sandro.lab
75 39624 michele.ar
	private static final Log log = LogFactory.getLog(WorkflowsController.class);
76 41356 michele.ar
77 42621 sandro.lab
	@Autowired
78 26600 sandro.lab
	private ISLookupClient isLookupClient;
79
80 42621 sandro.lab
	@Autowired
81 26600 sandro.lab
	private ISRegistryClient isRegistryClient;
82
83 42621 sandro.lab
	@Autowired
84 41339 michele.ar
	private RepoUIUtils repoUIUtils;
85
86 42621 sandro.lab
	@Autowired
87 42069 michele.ar
	private GraphLoader graphLoader;
88
89 42621 sandro.lab
	@Autowired
90 40094 michele.ar
	private ProcessRegistry graphProcessRegistry;
91 26600 sandro.lab
92 42621 sandro.lab
	@Autowired
93 26600 sandro.lab
	private WorkflowSectionGrouper workflowSectionGrouper;
94
95 42621 sandro.lab
	@Autowired
96 26600 sandro.lab
	private WorkflowExecutor workflowExecutor;
97
98
	@Resource(name = "msroWorkflowLogger")
99
	private DnetLogger dnetLogger;
100
101 42621 sandro.lab
	@Autowired
102 42174 michele.ar
	private UniqueServiceLocator serviceLocator;
103
104 41339 michele.ar
	@Value("${repo.ui.compatibilityLevels.vocabulary}")
105
	private String compatibilityLevelsVocabulary;
106
107 39948 michele.ar
	@RequestMapping("/ui/wf/list_workflows.json")
108 41339 michele.ar
	public @ResponseBody List<WorkflowItem> listWorflowsForSection(@RequestParam(value = "section", required = false) final String sectionName,
109 39624 michele.ar
			@RequestParam(value = "dsId", required = false) final String dsId)
110 41550 michele.ar
			throws ISLookUpException, IOException {
111 26600 sandro.lab
		if (sectionName != null) {
112 41339 michele.ar
			return this.workflowSectionGrouper.listWorflowsForSection(sectionName);
113 26600 sandro.lab
		} else if (dsId != null) {
114 41339 michele.ar
			return this.workflowSectionGrouper.listWorflowsForDatasource(dsId);
115 26600 sandro.lab
		} else {
116 42174 michele.ar
			return new ArrayList<>();
117 26600 sandro.lab
		}
118
	}
119
120 39948 michele.ar
	@RequestMapping("/ui/wf/workflow.html")
121 41339 michele.ar
	public void getWorkflowHtml(final HttpServletResponse res, @RequestParam(value = "id", required = true) final String id) throws Exception {
122 42097 michele.ar
		final SAXReader reader = new SAXReader();
123 41339 michele.ar
		final String profile = this.isLookupClient.getProfile(id);
124 42097 michele.ar
		final Document doc = reader.read(new StringReader(profile));
125 41482 michele.ar
		final Element dsNode = (Element) doc.selectSingleNode("//DATASOURCE");
126
		if (dsNode != null) {
127 42097 michele.ar
			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 42122 michele.ar
			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 42097 michele.ar
			}
140 41482 michele.ar
		}
141 42097 michele.ar
142 41482 michele.ar
		final ApplyXsltDom4j xslt = new ApplyXsltDom4j(new ClassPathResource("/eu/dnetlib/functionality/modular/ui/workflows/xslt/wf_profile2html.xslt"));
143 42097 michele.ar
144 39743 michele.ar
		res.setContentType("text/html");
145 41838 michele.ar
		IOUtils.copy(new StringReader(xslt.apply(doc)), res.getOutputStream());
146 26600 sandro.lab
	}
147
148 42179 michele.ar
	@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 42288 michele.ar
		final Graph graph = this.graphLoader.loadGraph(doc, new HashMap<>());
154 42179 michele.ar
155 42288 michele.ar
		return GraphDetails.from(graph);
156 42179 michele.ar
	}
157
158 42122 michele.ar
	@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 41339 michele.ar
	@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 41356 michele.ar
212
		final Node ifcNode = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
213 43444 sandro.lab
214
		final String profileId = doc.valueOf("//RESOURCE_IDENTIFIER/@value");
215
216 41356 michele.ar
		final String protocol = ifcNode.valueOf("./ACCESS_PROTOCOL");
217 41339 michele.ar
		final Element extra = doc.getRootElement().addElement("extra_info");
218 41356 michele.ar
219 41339 michele.ar
		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 41356 michele.ar
		final Element parameters = extra.addElement("parameters");
226 42122 michele.ar
		for (final Object o : ifcNode.selectNodes("./ACCESS_PROTOCOL/@*")) {
227 41356 michele.ar
			final Element p = parameters.addElement("param");
228 42122 michele.ar
			p.addAttribute("name", ((Node) o).getName());
229
			p.setText(((Node) o).getText());
230
		}
231 41356 michele.ar
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 41480 michele.ar
		final Element wfs = extra.addElement("workflows");
240 43444 sandro.lab
		for (final WorkflowItem item : this.isLookupClient.listWorflowsForApi(profileId, ifaceId)) {
241 41480 michele.ar
			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 42174 michele.ar
			if (item.isDestroy()) {
246
				wf.addAttribute("destroy", "1");
247
			}
248 41480 michele.ar
		}
249 43444 sandro.lab
		final Map<String, String> params = new HashMap<>();
250 41356 michele.ar
		params.put("profileId", doc.valueOf("//RESOURCE_IDENTIFIER/@value"));
251 41339 michele.ar
		params.put("ifaceId", ifaceId);
252 41356 michele.ar
		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 41339 michele.ar
259 41356 michele.ar
		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 41339 michele.ar
		final ApplyXsltDom4j xslt = new ApplyXsltDom4j(new ClassPathResource("/eu/dnetlib/functionality/modular/ui/workflows/xslt/repoApi.xslt"), params);
268
269
		res.setContentType("text/html");
270 41356 michele.ar
271 41838 michele.ar
		IOUtils.copy(new StringReader(xslt.apply(doc)), res.getOutputStream());
272 26600 sandro.lab
	}
273
274 39948 michele.ar
	@RequestMapping("/ui/wf/wf.start")
275 41339 michele.ar
	public @ResponseBody ProcessInfo startWorkflow(@RequestParam(value = "id", required = true) final String id) throws Exception {
276 41550 michele.ar
		final String procId = this.workflowExecutor.startWorkflow(id, null);
277 42069 michele.ar
		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 39798 michele.ar
		}
298 42069 michele.ar
299 43063 michele.ar
		final Node node = doc.selectSingleNode("//NODE[@name='" + nodeName + "']");
300 42069 michele.ar
		final Map<String, Object> params =
301 43063 michele.ar
				GraphNode.newNode(nodeName, node.valueOf("@type"),
302
						this.graphLoader.calculateParamsForNode(node, globalParams))
303 43083 claudio.at
						.resolveParamsWithNoEnv();
304 42069 michele.ar
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 26600 sandro.lab
	}
327
328 42284 michele.ar
	@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 39948 michele.ar
	@RequestMapping("/ui/wf/update_workflow.do")
355 41339 michele.ar
	public @ResponseBody boolean updateWorkflow(@RequestParam(value = "json", required = true) final String json) throws Exception {
356 26600 sandro.lab
357 39792 michele.ar
		final WorkflowUpdateInfo info = (new Gson()).fromJson(json, WorkflowUpdateInfo.class);
358 39624 michele.ar
359 39781 michele.ar
		log.info("Updating workflow " + info.getWfId());
360 26600 sandro.lab
361 41339 michele.ar
		final String xml = this.isLookupClient.getProfile(info.getWfId());
362
		final boolean res = this.isRegistryClient.updateWorkflowProfile(info.getWfId(), xml, info);
363 26600 sandro.lab
364 29227 michele.ar
		return res;
365 26600 sandro.lab
	}
366
367 39948 michele.ar
	@RequestMapping("/ui/wf/proc.kill")
368 41339 michele.ar
	public @ResponseBody boolean killProcessWorkflow(@RequestParam(value = "id", required = true) final String id) throws Exception {
369
		this.graphProcessRegistry.findProcess(id).kill();
370 28946 michele.ar
		return true;
371 26600 sandro.lab
	}
372 39624 michele.ar
373 39948 michele.ar
	@RequestMapping("/ui/wf/journal.range")
374 41339 michele.ar
	public @ResponseBody Collection<ProcessInfo> rangeWfJournal(@RequestParam(value = "start", required = true) final String start,
375 26600 sandro.lab
			@RequestParam(value = "end", required = true) final String end) throws Exception {
376 39624 michele.ar
377 41838 michele.ar
		final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
378 41872 sandro.lab
		final LocalDateTime startDate = LocalDate.parse(start, formatter).atTime(0, 0);
379
		final LocalDateTime endDate = LocalDate.parse(end, formatter).atTime(23, 59);
380 39624 michele.ar
381 42174 michele.ar
		final Iterator<Map<String, String>> iterator = this.dnetLogger.range(startDate, endDate);
382
		final LocalDateTime now = LocalDateTime.now();
383 39624 michele.ar
384 42174 michele.ar
		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 27010 michele.ar
		if (startDate.isBefore(now) && endDate.isAfter(now)) {
389 41339 michele.ar
			for (final WorkflowProcess proc : this.graphProcessRegistry.listProcesses()) {
390 41957 michele.ar
				res.put(proc.getId(), new ProcessInfo(proc));
391 27010 michele.ar
			}
392
		}
393 39624 michele.ar
394 27010 michele.ar
		return res.values();
395 26600 sandro.lab
	}
396 27010 michele.ar
397 39948 michele.ar
	@RequestMapping("/ui/wf/journal.find")
398 41339 michele.ar
	public @ResponseBody List<ProcessInfo> findWfJournal(@RequestParam(value = "wfs", required = true) final String wfs) {
399 39848 michele.ar
		final Map<String, ProcessInfo> map = Maps.newHashMap();
400 39624 michele.ar
401 39848 michele.ar
		final Set<String> wfFilter = Sets.newHashSet(Splitter.on(",").omitEmptyStrings().trimResults().split(wfs));
402 39624 michele.ar
403 41339 michele.ar
		for (final String wfId : wfFilter) {
404 42174 michele.ar
			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 27010 michele.ar
		}
409 39624 michele.ar
410 41339 michele.ar
		for (final WorkflowProcess proc : this.graphProcessRegistry.listProcesses()) {
411 42301 michele.ar
			if (wfFilter.contains(proc.getProfileId())) {
412
				map.put(proc.getProfileId(), new ProcessInfo(proc));
413 26994 michele.ar
			}
414
		}
415 39624 michele.ar
416 42174 michele.ar
		return map.values().stream().sorted(new Comparator<ProcessInfo>() {
417 39848 michele.ar
418
			@Override
419
			public int compare(final ProcessInfo p1, final ProcessInfo p2) {
420 39915 michele.ar
				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 39848 michele.ar
			}
428 42174 michele.ar
		}).collect(Collectors.toList());
429 26994 michele.ar
	}
430 39624 michele.ar
431 39948 michele.ar
	@RequestMapping("/ui/wf/journal_byFamily.find")
432 41339 michele.ar
	public @ResponseBody Collection<ProcessInfo> findWfJournalByFamily(@RequestParam(value = "family", required = true) final String family)
433
			throws IOException {
434 42174 michele.ar
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 29656 michele.ar
	}
442 39624 michele.ar
443 39948 michele.ar
	@RequestMapping("/ui/wf/journal.get")
444 41339 michele.ar
	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 30212 michele.ar
448 42130 michele.ar
		final ProcessInfo info = (process != null) ? new ProcessInfo(process) : new ProcessInfo(logs);
449
450 30212 michele.ar
		if (logs != null && !logs.isEmpty()) {
451 42174 michele.ar
			logs.keySet().stream().sorted().forEach(k -> info.getOutputParams().add(new EnvParam(k, logs.get(k))));
452 30212 michele.ar
		}
453 39624 michele.ar
454 39798 michele.ar
		return info;
455
	}
456 39624 michele.ar
457 39948 michele.ar
	@RequestMapping(value = "/ui/wf/saveParams.do")
458 41339 michele.ar
	public @ResponseBody boolean saveWorkflowParams(@RequestParam(value = "wf", required = true) final String wfId,
459 39624 michele.ar
			@RequestParam(value = "params", required = true) final String jsonParams) throws Exception {
460
461 41339 michele.ar
		final String xml = this.isLookupClient.getProfile(wfId);
462 39624 michele.ar
463 41339 michele.ar
		final Map<String, String> params = new Gson().fromJson(jsonParams, new TypeToken<Map<String, String>>() {}.getType());
464 39624 michele.ar
465 41339 michele.ar
		return this.isRegistryClient.updateWorkflowProfile(wfId, xml, params);
466 28130 michele.ar
	}
467
468 40578 michele.ar
	@RequestMapping(value = "/ui/wf/obtainSubWorkflows.do")
469 41339 michele.ar
	public @ResponseBody List<Map<String, String>> obtainSubWorkflows(@RequestParam(value = "id", required = true) final String wfId) {
470
		return this.isLookupClient.obtainSubWorkflows(wfId);
471 40578 michele.ar
	}
472 41423 michele.ar
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 41430 michele.ar
480
	@RequestMapping("/ui/wf/repohi.start")
481 41480 michele.ar
	public @ResponseBody List<String> newRepoWorkflow(@RequestParam(value = "id", required = true) final String repoId,
482 41430 michele.ar
			@RequestParam(value = "iface", required = true) final String ifaceId,
483
			@RequestParam(value = "wf", required = true) final String wfId) throws Exception {
484
485 42174 michele.ar
		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 43444 sandro.lab
					log.error("Error updating activation status of " + repoId, e);
493 42174 michele.ar
				}
494
			}
495
496
			@Override
497
			public void onFail() {}
498
		});
499
500
		return Arrays.asList(procId);
501 41430 michele.ar
	}
502
503
	@RequestMapping("/ui/wf/repobye.start")
504 42174 michele.ar
	public @ResponseBody List<String> destroyRepoWorkflow(@RequestParam(value = "wf", required = true) final String wf)
505 41430 michele.ar
			throws Exception {
506 42174 michele.ar
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 43063 michele.ar
526
		final Map<String, String> params = GraphNode.newNode("REPO_BYE", "REPO_BYE",
527
				this.graphLoader.calculateParamsForNode(node, globalParams))
528 43083 claudio.at
				.resolveParamsWithNoEnv().entrySet()
529 42174 michele.ar
				.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 41430 michele.ar
	}
552
553 42174 michele.ar
	private ProcessInfo toProcessInfo(final Map<String, String> input) {
554
		final ProcessInfo info = new ProcessInfo();
555 41872 sandro.lab
556 42174 michele.ar
		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 41872 sandro.lab
566 42174 michele.ar
		return info;
567 41872 sandro.lab
568
	}
569
570 26600 sandro.lab
}