Project

General

Profile

1
package eu.dnetlib.enabling.datasources;
2

    
3
import java.io.StringReader;
4
import java.text.ParseException;
5
import java.util.ArrayList;
6
import java.util.Arrays;
7
import java.util.Collections;
8
import java.util.Date;
9
import java.util.HashMap;
10
import java.util.List;
11
import java.util.Map;
12
import java.util.Objects;
13
import java.util.Optional;
14
import java.util.stream.Collectors;
15

    
16
import org.antlr.stringtemplate.StringTemplate;
17
import org.apache.commons.io.IOUtils;
18
import org.apache.commons.lang3.StringEscapeUtils;
19
import org.apache.commons.lang3.StringUtils;
20
import org.apache.commons.lang3.math.NumberUtils;
21
import org.apache.commons.logging.Log;
22
import org.apache.commons.logging.LogFactory;
23
import org.dom4j.Document;
24
import org.dom4j.Element;
25
import org.dom4j.Node;
26
import org.dom4j.io.SAXReader;
27
import org.quartz.CronExpression;
28
import org.springframework.beans.factory.annotation.Autowired;
29
import org.springframework.core.io.ClassPathResource;
30
import org.springframework.stereotype.Component;
31

    
32
import com.google.common.collect.Sets;
33

    
34
import eu.dnetlib.clients.dsManager.BrowsableField;
35
import eu.dnetlib.clients.dsManager.BrowseTerm;
36
import eu.dnetlib.clients.dsManager.DatasourceDesc;
37
import eu.dnetlib.clients.dsManager.DatasourcePoint;
38
import eu.dnetlib.clients.dsManager.IfaceDesc;
39
import eu.dnetlib.clients.dsManager.SearchInterfacesEntry;
40
import eu.dnetlib.clients.dsManager.SimpleDatasourceDesc;
41
import eu.dnetlib.enabling.is.DnetInformationServiceException;
42
import eu.dnetlib.enabling.is.InformationServiceController;
43

    
44
@Component
45
public class SimpleDatasourceManagerCore implements DatasourceManagerCore {
46

    
47
	private static final Log log = LogFactory.getLog(SimpleDatasourceManagerCore.class);
48

    
49
	@Autowired
50
	private InformationServiceController is;
51

    
52
	private static final List<BrowsableField> browsableFields = Arrays.asList(
53
			new XmlBrowsableField("country", "Datasource countries", "../../COUNTRY/text()", "dnet:countries"),
54
			new XmlBrowsableField("type", "API typologies", "@typology/string()", "dnet:datasource_typologies"),
55
			new XmlBrowsableField("protocol", "API protocols", "ACCESS_PROTOCOL/text()", "dnet:protocols"),
56
			new XmlBrowsableField("compliance", "API compatibility levels",
57
					"concat(substring(./INTERFACE_EXTRA_FIELD[@name='overriding_compliance'], 1, number(boolean(./INTERFACE_EXTRA_FIELD[@name='overriding_compliance'])) * string-length(./INTERFACE_EXTRA_FIELD[@name='overriding_compliance'])), substring(@compliance, 1, number(not(boolean(./INTERFACE_EXTRA_FIELD[@name='overriding_compliance']))) * string-length(@compliance)))",
58
					"dnet:compatibilityLevel"));
59

    
60
	private ClassPathResource findReposQueryTmpl = new ClassPathResource("/templates/findRepos.xquery.st");
61
	private ClassPathResource browseRepoApisQueryTmpl = new ClassPathResource("/templates/browseRepoApis.xquery.st");
62
	private ClassPathResource findRepoApisQueryTmpl = new ClassPathResource("/templates/findRepoApis.xquery.st");
63
	private ClassPathResource findReposMapQuery = new ClassPathResource("/templates/findReposMap.xquery");
64
	private ClassPathResource simpleFindReposQueryTmpl = new ClassPathResource("/templates/simpleFindRepos.xquery.st");
65

    
66
	public static final String OVERRIDING_COMPLIANCE_FIELD = "overriding_compliance";
67

    
68
	@Override
69
	public String addDatasource(final DatasourceDesc datasourceDescription) throws DatasourceManagerServiceException {
70
		try {
71
			final String profile = DatasourceDescToProfile.convert(datasourceDescription);
72
			return is.registerProfile(profile);
73
		} catch (final Exception e) {
74
			log.error("Error registering profile", e);
75
			throw new DatasourceManagerServiceException("Error registering profile", e);
76
		}
77
	}
78

    
79
	@Override
80
	public List<DatasourceDesc> listDatasources(final String compliance,
81
			final String contentDescription,
82
			final String collectedFrom) throws DatasourceManagerServiceException {
83
		try {
84
			final StringTemplate st = new StringTemplate();
85
			st.setTemplate(IOUtils.toString(findReposQueryTmpl.getInputStream()));
86

    
87
			final Map<String, String> conds = new HashMap<>();
88

    
89
			if (StringUtils.isNotBlank(compliance)) {
90
				conds.put("//INTERFACE/@compliance", compliance);
91
			}
92
			if (StringUtils.isNotBlank(contentDescription)) {
93
				conds.put("//INTERFACE/@contentDescription", contentDescription);
94
			}
95
			if (StringUtils.isNotBlank(collectedFrom)) {
96
				// NOT USED
97
			}
98

    
99
			if (!conds.isEmpty()) {
100
				st.setAttribute("conds", conds);
101
			}
102

    
103
			final List<String> list = is.find(st.toString());
104

    
105
			return list.stream().map(new ProfileToDatasourceDesc()).collect(Collectors.toList());
106
		} catch (final Exception e) {
107
			log.error("Error listing datasources", e);
108
			throw new DatasourceManagerServiceException("Error listing datasources", e);
109
		}
110
	}
111

    
112
	@Override
113
	public boolean updateSQL(final String dsId, final String sql, final boolean delete) throws DatasourceManagerServiceException {
114
		throw new DatasourceManagerServiceException("NOT IMPLEMENTED");
115
	}
116

    
117
	@Override
118
	public boolean bulkUpdateApiExtraFields(final String dsId, final String ifaceId, final Map<String, String> fields)
119
			throws DatasourceManagerServiceException {
120
		try {
121
			final String profile = obtainProfile(dsId);
122

    
123
			final SAXReader reader = new SAXReader();
124
			final Document doc = reader.read(new StringReader(profile));
125

    
126
			final Element iface = (Element) doc.selectSingleNode("//INTERFACE[@id='" + ifaceId + "']");
127
			if (iface != null) {
128

    
129
				while (iface.selectNodes("./INTERFACE_EXTRA_FIELD").size() > 0) {
130
					iface.selectSingleNode("./INTERFACE_EXTRA_FIELD").detach();
131
				}
132

    
133
				fields.entrySet().forEach(e -> {
134
					if ((e.getValue() != null) && !e.getValue().isEmpty()) {
135
						final Element field = iface.addElement("INTERFACE_EXTRA_FIELD");
136
						field.addAttribute("name", e.getKey());
137
						field.addText(e.getValue());
138
					}
139
				});
140
				is.updateProfile(dsId, doc.asXML());
141
			} else {
142
				log.error("Invalid interface: " + ifaceId);
143
				throw new DatasourceManagerServiceException("Missing interface: " + ifaceId);
144
			}
145
		} catch (final Exception e) {
146
			log.error("Error updating API of profile: " + dsId);
147
			throw new DatasourceManagerServiceException("Error updating API of profile: " + dsId, e);
148
		}
149
		return true;
150
	}
151

    
152
	@Override
153
	public List<BrowsableField> listBrowsableFields() throws DatasourceManagerServiceException {
154
		return browsableFields;
155
	}
156

    
157
	@Override
158
	public List<BrowseTerm> browseField(final String f) throws DatasourceManagerServiceException {
159
		final List<BrowseTerm> list = new ArrayList<>();
160

    
161
		try {
162
			final XmlBrowsableField field = findBrowseField(f);
163
			if (field != null) {
164
				final StringTemplate st = new StringTemplate(IOUtils.toString(browseRepoApisQueryTmpl.getInputStream()));
165
				st.setAttribute("xpath", field.getXpath());
166

    
167
				final Map<String, String> terms = fetchVocabularyTerms(field.getVocabulary());
168

    
169
				for (final String s : is.find(st.toString())) {
170
					final String[] arr = s.split("@-@-@");
171
					final String id = arr[0].trim();
172
					final int count = NumberUtils.toInt(arr[1].trim(), 0);
173
					list.add(new BrowseTerm(id, findLabel(id, terms), count));
174
				}
175
			}
176
		} catch (final Exception e) {
177
			log.error("Error browsing field " + f, e);
178
		}
179

    
180
		return list;
181
	}
182

    
183
	@Override
184
	public List<SearchInterfacesEntry> searchInterface(final String field, final String value)
185
			throws DatasourceManagerServiceException {
186
		try {
187

    
188
			final StringTemplate st = new StringTemplate();
189
			st.setTemplate(IOUtils.toString(findRepoApisQueryTmpl.getInputStream()));
190

    
191
			if (field.equalsIgnoreCase("__search__")) {
192
				st.setAttribute("cond", "contains(../..//(*|@*)/lower-case(.), '" + StringEscapeUtils.escapeXml(value.toLowerCase()) + "')");
193
			} else {
194
				final XmlBrowsableField f = findBrowseField(field);
195
				if (f != null) {
196
					st.setAttribute("cond", f.getXpath() + "='" + StringEscapeUtils.escapeXml(value) + "'");
197
				} else {
198
					return new ArrayList<>();
199
				}
200
			}
201

    
202
			final String query = st.toString();
203

    
204
			final SAXReader reader = new SAXReader();
205

    
206
			return is.find(query).stream()
207
					.map(it -> convertSearchInterface(it, reader)).collect(Collectors.toList());
208

    
209
		} catch (final Exception e) {
210
			log.error("Error searching field " + field + " - value: " + value, e);
211
		}
212
		return new ArrayList<>();
213
	}
214

    
215
	@Override
216
	public List<DatasourcePoint> getDatasourceMap() throws DatasourceManagerServiceException {
217
		try {
218
			final SAXReader reader = new SAXReader();
219

    
220
			final String query = IOUtils.toString(findReposMapQuery.getInputStream());
221
			return is.find(query)
222
					.stream()
223
					.map(s -> {
224
						try {
225
							final Document doc = reader.read(new StringReader(s));
226
							return new DatasourcePoint(
227
									doc.valueOf("//dsId"),
228
									doc.valueOf("//name"),
229
									Float.parseFloat(doc.valueOf("//lat")),
230
									Float.parseFloat(doc.valueOf("//lng")));
231
						} catch (final Exception e) {
232
							log.error(e);
233
							return null;
234
						}
235
					})
236
					.filter(Objects::nonNull)
237
					.collect(Collectors.toList());
238

    
239
		} catch (final Exception e) {
240
			log.error("Error obtaing repo map entries", e);
241
		}
242
		return new ArrayList<>();
243
	}
244

    
245
	@Override
246
	public List<SimpleDatasourceDesc> simpleListDatasourcesByType(final String type) throws DatasourceManagerServiceException {
247
		try {
248
			final List<SimpleDatasourceDesc> list = new ArrayList<>();
249

    
250
			final StringTemplate st = new StringTemplate(IOUtils.toString(simpleFindReposQueryTmpl.getInputStream()));
251
			st.setAttribute("type", type);
252

    
253
			for (final String s : is.find(st.toString())) {
254
				final SimpleDatasourceDesc r = new SimpleDatasourceDesc();
255
				final String[] arr = s.split("@=@");
256
				r.setId(arr[0].trim());
257
				r.setName(arr[1].trim());
258
				r.setOrigId(arr[2].trim());
259
				r.setApis(Sets.newHashSet(arr[3].replaceAll("\\s", "").split(",")));
260
				r.setTypology(type);
261
				list.add(r);
262
			}
263

    
264
			Collections.sort(list);
265

    
266
			return list;
267
		} catch (final Exception e) {
268
			log.error("Error listing repos", e);
269
		}
270
		return new ArrayList<>();
271
	}
272

    
273
	@Override
274
	public boolean deleteDatasource(final String dsId) throws DatasourceManagerServiceException {
275
		try {
276
			return is.deleteProfile(fixDsId(dsId));
277
		} catch (final DnetInformationServiceException e) {
278
			log.error("Error deleting profile " + dsId, e);
279
			throw new DatasourceManagerServiceException("Error deleting profile " + dsId, e);
280
		}
281
	}
282

    
283
	private String fixDsId(final String dsId) throws DatasourceManagerServiceException {
284
		if (dsId.startsWith("entity/datasource/")) {
285
			return dsId;
286
		} else {
287
			try {
288
				return is.find("for $x in collection('/db/DRIVER/entity/datasource') "
289
						+ "where $x//DATASOURCE_ORIGINAL_ID = '" + dsId + "' "
290
						+ "return $x//RESOURCE_IDENTIFIER/@value/string()").get(0);
291
			} catch (final Throwable e) {
292
				throw new DatasourceManagerServiceException("Invalid id: " + dsId, e);
293
			}
294
		}
295
	}
296

    
297
	@Override
298
	public DatasourceDesc getDatasource(final String dsId) throws DatasourceManagerServiceException {
299
		try {
300
			final String profile = obtainProfile(fixDsId(dsId));
301
			return ProfileToDatasourceDesc.convert(profile);
302
		} catch (final Exception e) {
303
			log.error("Error accessing profile: " + dsId, e);
304
			throw new DatasourceManagerServiceException("Error accessing profile " + dsId, e);
305
		}
306
	}
307

    
308
	@Override
309
	public boolean updateLevelOfCompliance(final String dsId, final String ifaceId, final String level, final boolean override)
310
			throws DatasourceManagerServiceException {
311
		try {
312
			final String profId = fixDsId(dsId);
313

    
314
			if (override) {
315
				final String profile = obtainProfile(profId);
316
				final SAXReader reader = new SAXReader();
317
				final Document doc = reader.read(new StringReader(profile));
318

    
319
				final Element iface = (Element) doc.selectSingleNode("//INTERFACE[@id='" + ifaceId + "']");
320
				if (iface != null) {
321
					final Map<String, String> fields = new HashMap<>();
322

    
323
					if (!StringUtils.isEmpty(level)) {
324
						fields.put(OVERRIDING_COMPLIANCE_FIELD, level);
325
					}
326

    
327
					while (iface.selectNodes("./INTERFACE_EXTRA_FIELD").size() > 0) {
328
						final Node node = iface.selectSingleNode("./INTERFACE_EXTRA_FIELD");
329
						final String name = node.valueOf("@name");
330

    
331
						if (!name.equals(OVERRIDING_COMPLIANCE_FIELD)) {
332
							fields.put(node.valueOf("@name"), node.getText());
333
						}
334
						node.detach();
335
					}
336

    
337
					for (final Map.Entry<String, String> e : fields.entrySet()) {
338
						if ((e.getValue() != null) && !e.getValue().isEmpty()) {
339
							final Element field = iface.addElement("INTERFACE_EXTRA_FIELD");
340
							field.addAttribute("name", e.getKey());
341
							field.addText(e.getValue());
342
						}
343
					}
344
					is.updateProfile(profId, doc.asXML());
345
				} else {
346
					log.error("Invalid interface: " + ifaceId);
347
					throw new DatasourceManagerServiceException("Missing interface: " + ifaceId);
348
				}
349
				return true;
350
			} else {
351
				final String xq =
352
						String.format("for $x in doc('/db/DRIVER/%s')//INTERFACE[@id = '%s']/@compliance return update replace $x with '%s'",
353
								profId, ifaceId, level);
354
				return is.xupdate(xq);
355
			}
356
		} catch (final Exception e) {
357
			log.error("Error updating profile: " + dsId, e);
358
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
359
		}
360
	}
361

    
362
	@Override
363
	public boolean resetLevelOfCompliance(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
364
		return deleteExtraField(dsId, ifaceId, OVERRIDING_COMPLIANCE_FIELD);
365
	}
366

    
367
	@Override
368
	public boolean updateBaseUrl(final String dsId, final String ifaceId, final String baseUrl) throws DatasourceManagerServiceException {
369
		try {
370
			final String xq =
371
					String.format("for $x in doc('/db/DRIVER/%s')//INTERFACE[@id = '%s']/BASE_URL return update replace $x with <BASE_URL>%s</BASE_URL>",
372
							fixDsId(dsId), ifaceId, baseUrl);
373
			return is.xupdate(xq);
374
		} catch (final Exception e) {
375
			log.error("Error updating profile: " + dsId, e);
376
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
377
		}
378
	}
379

    
380
	@Override
381
	public boolean updateActivationStatus(final String dsId, final String ifaceId, final boolean active) throws DatasourceManagerServiceException {
382
		try {
383
			final String xq =
384
					String.format("for $x in doc('/db/DRIVER/%s')//INTERFACE[@id = '%s']/@active return update replace $x with '%s'",
385
							fixDsId(dsId), ifaceId, active);
386
			return is.xupdate(xq);
387
		} catch (final Exception e) {
388
			log.error("Error updating profile: " + dsId, e);
389
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
390
		}
391
	}
392

    
393
	@Override
394
	public boolean updateContentDescription(final String dsId, final String ifaceId, final String desc) throws DatasourceManagerServiceException {
395
		try {
396
			final String xq =
397
					String.format("for $x in doc('/db/DRIVER/%s')//INTERFACE[@id = '%s']/@contentDescription return update replace $x with '%s'",
398
							fixDsId(dsId), ifaceId, desc);
399
			return is.xupdate(xq);
400
		} catch (final Exception e) {
401
			log.error("Error updating profile: " + dsId, e);
402
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
403
		}
404
	}
405

    
406
	@Override
407
	public boolean updateExtraField(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
408
			throws DatasourceManagerServiceException {
409

    
410
		final String profId = fixDsId(dsId);
411
		try {
412
			final String profile = obtainProfile(profId);
413
			final Document doc = new SAXReader().read(new StringReader(profile));
414

    
415
			final Node ifcNode = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
416
			final Node node = ifcNode.selectSingleNode("./INTERFACE_EXTRA_FIELD[@name = '" + field + "']");
417
			if (node != null) {
418
				node.setText(value);
419
			} else {
420
				final Element e = ((Element) ifcNode).addElement("INTERFACE_EXTRA_FIELD");
421
				e.addAttribute("name", field);
422
				e.setText(value);
423
			}
424
			return is.updateProfile(profId, doc.asXML());
425
		} catch (final Exception e) {
426
			log.error("Error updating profile: " + dsId, e);
427
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
428
		}
429
	}
430

    
431
	@Override
432
	public boolean updateAccessParam(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
433
			throws DatasourceManagerServiceException {
434
		final String profId = fixDsId(dsId);
435

    
436
		try {
437

    
438
			final String profile = obtainProfile(profId);
439
			final Document doc = new SAXReader().read(new StringReader(profile));
440

    
441
			final Node node = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']/ACCESS_PROTOCOL");
442
			((Element) node).addAttribute(field, value);
443

    
444
			return is.updateProfile(profId, doc.asXML());
445
		} catch (final Exception e) {
446
			log.error("Error updating profile: " + profId, e);
447
			throw new DatasourceManagerServiceException("Error updating profile: " + profId, e);
448
		}
449
	}
450

    
451
	@Override
452
	public boolean deleteAccessParam(final String dsId, final String ifaceId, final String field) throws DatasourceManagerServiceException {
453
		final String profId = fixDsId(dsId);
454

    
455
		try {
456

    
457
			final String profile = obtainProfile(profId);
458
			final Document doc = new SAXReader().read(new StringReader(profile));
459

    
460
			final Node ap = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']/ACCESS_PROTOCOL/@" + field);
461
			if (ap != null) {
462
				ap.detach();
463

    
464
			}
465
			return is.updateProfile(profId, doc.asXML());
466
		} catch (final Exception e) {
467
			log.error("Error updating profile: " + profId, e);
468
			throw new DatasourceManagerServiceException("Error updating profile: " + profId, e);
469
		}
470
	}
471

    
472
	@Override
473
	public boolean deleteExtraField(final String dsId, final String ifaceId, final String field) throws DatasourceManagerServiceException {
474
		final String profId = fixDsId(dsId);
475

    
476
		try {
477

    
478
			final String profile = obtainProfile(profId);
479

    
480
			System.out.println(profile);
481

    
482
			final Document doc = new SAXReader().read(new StringReader(profile));
483

    
484
			final Node ef = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']/INTERFACE_EXTRA_FIELD[@name = '" + field + "']");
485
			if (ef != null) {
486
				ef.detach();
487
			}
488
			return is.updateProfile(profId, doc.asXML());
489
		} catch (final Exception e) {
490
			log.error("Error updating profile: " + profId, e);
491
			throw new DatasourceManagerServiceException("Error updating profile: " + profId, e);
492
		}
493
	}
494

    
495
	@Override
496
	public boolean addInterface(final String dsId, final IfaceDesc iface) throws DatasourceManagerServiceException {
497
		final String profId = fixDsId(dsId);
498

    
499
		try {
500
			final String profile = obtainProfile(profId);
501
			final Document doc = new SAXReader().read(new StringReader(profile));
502

    
503
			final Node node = doc.selectSingleNode("//INTERFACE[@id = '" + iface.getId() + "']");
504
			if (node != null) {
505
				node.detach();
506
			}
507

    
508
			((Element) doc.selectSingleNode("//INTERFACES")).add(DatasourceDescToProfile.ifaceDescToNode(iface));
509

    
510
			return is.updateProfile(profId, doc.asXML());
511
		} catch (final Exception e) {
512
			log.error("Error updating profile: " + profId, e);
513
			throw new DatasourceManagerServiceException("Error updating profile: " + profId, e);
514
		}
515
	}
516

    
517
	@Override
518
	public boolean deleteInterface(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
519
		final String profId = fixDsId(dsId);
520

    
521
		try {
522
			final String profile = obtainProfile(profId);
523
			final Document doc = new SAXReader().read(new StringReader(profile));
524

    
525
			final Node node = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
526
			if (node != null) {
527
				node.detach();
528
			}
529

    
530
			return is.updateProfile(profId, doc.asXML());
531
		} catch (final Exception e) {
532
			log.error("Error updating profile: " + profId, e);
533
			throw new DatasourceManagerServiceException("Error updating profile: " + profId, e);
534
		}
535
	}
536

    
537
	@Override
538
	public Date findNextScheduledExecution(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
539
		final String xquery = "/*[.//DATAPROVIDER/@interface='" + ifaceId + "' and .//SCHEDULING/@enabled='true']//CRON/text()";
540
		try {
541
			final List<String> cronExpressions = is.find(xquery);
542
			return cronExpressions.isEmpty() ? null : (new CronExpression(cronExpressions.get(0))).getNextValidTimeAfter(new Date());
543
		} catch (final DnetInformationServiceException e) {
544
			log.error("Error in xquery: " + xquery, e);
545
			throw new DatasourceManagerServiceException("Error in xquery: " + xquery, e);
546
		} catch (final ParseException e) {
547
			log.error("Error parsing cron expression", e);
548
			throw new DatasourceManagerServiceException("Error parsing cron expression", e);
549
		}
550
	}
551

    
552
	@Override
553
	public boolean bulkUpdateApiAccessParams(final String dsId, final String ifaceId, final Map<String, String> params)
554
			throws DatasourceManagerServiceException {
555

    
556
		final String profId = fixDsId(dsId);
557

    
558
		try {
559
			final String profile = obtainProfile(profId);
560

    
561
			final SAXReader reader = new SAXReader();
562
			final Document doc = reader.read(new StringReader(profile));
563

    
564
			final Element accessNode = (Element) doc.selectSingleNode("//INTERFACE[@id='" + ifaceId + "']/ACCESS_PROTOCOL");
565
			if (accessNode != null) {
566
				while (accessNode.attributes().size() > 0) {
567
					accessNode.selectSingleNode("@*").detach();
568
				}
569
				for (final Map.Entry<String, String> e : params.entrySet()) {
570
					if ((e.getValue() != null) && !e.getValue().isEmpty()) {
571
						if (e.getKey().equalsIgnoreCase("baseUrl")) {
572
							doc.selectSingleNode("//INTERFACE[@id='" + ifaceId + "']/BASE_URL").setText(e.getValue());
573
						} else {
574
							accessNode.addAttribute(e.getKey(), e.getValue());
575
						}
576
					}
577
				}
578
				is.updateProfile(profId, doc.asXML());
579
			} else {
580
				log.error("Invalid interface: " + ifaceId);
581
				throw new DatasourceManagerServiceException("Missing interface: " + ifaceId);
582
			}
583
		} catch (final Exception e) {
584
			log.error("Error updating API of profile: " + profId);
585
			throw new DatasourceManagerServiceException("Error updating API of profile: " + profId, e);
586
		}
587
		return true;
588
	}
589

    
590
	private XmlBrowsableField findBrowseField(final String id) {
591

    
592
		final Optional<XmlBrowsableField> res = browsableFields.stream()
593
				.filter(f -> f.getId().equals(id) && (f instanceof XmlBrowsableField))
594
				.map(f -> (XmlBrowsableField) f)
595
				.findFirst();
596

    
597
		return res.isPresent() ? res.get() : null;
598
	}
599

    
600
	public Map<String, String> fetchVocabularyTerms(final String voc) throws DnetInformationServiceException {
601
		final String xquery = "for $x in collection('/db/DRIVER/conf/vocabulary')[.//VOCABULARY_NAME/@code = '"
602
				+ voc.trim() + "']//TERM return concat($x/@code, ' @@@ ', $x/@english_name)";
603

    
604
		final Map<String, String> map = new HashMap<>();
605
		for (final String s : is.find(xquery)) {
606
			final String[] arr = s.split("@@@");
607
			map.put(arr[0].trim(), arr[1].trim());
608
		}
609
		return map;
610
	}
611

    
612
	private String findLabel(final String code, final Map<String, String> terms) {
613
		return terms.containsKey(code) ? terms.get(code) : code;
614
	}
615

    
616
	private SearchInterfacesEntry convertSearchInterface(final String s, final SAXReader reader) {
617
		final SearchInterfacesEntry iface = new SearchInterfacesEntry();
618
		try {
619
			final Document doc = reader.read(new StringReader(s));
620
			final String country = doc.valueOf("//REPO/@country");
621

    
622
			iface.setDsId(doc.valueOf("//REPO/@id"));
623
			iface.setCountry(StringUtils.isEmpty(country) ? "-" : country.toUpperCase());
624
			iface.setDsName(doc.valueOf("//REPO/@name"));
625
			iface.setPrefix(doc.valueOf("//REPO/@prefix"));
626

    
627
			final Node ifcNode = doc.selectSingleNode("//INTERFACE");
628

    
629
			iface.setId(ifcNode.valueOf("./@id"));
630
			iface.setActive(Boolean.valueOf(ifcNode.valueOf("./@active")));
631
			iface.setProtocol(ifcNode.valueOf("./ACCESS_PROTOCOL/text()"));
632

    
633
			final String overCompliance = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='overriding_compliance']");
634
			if (StringUtils.isEmpty(overCompliance)) {
635
				iface.setCompliance(ifcNode.valueOf("@compliance"));
636
			} else {
637
				iface.setCompliance(overCompliance);
638
			}
639

    
640
			final String lastAggregationDate = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_aggregation_date']");
641
			if (!StringUtils.isEmpty(lastAggregationDate)) {
642
				iface.setAggrDate(lastAggregationDate);
643
			} else {
644
				final String lastDownloadDate = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_download_date']");
645
				if (!StringUtils.isEmpty(lastDownloadDate)) {
646
					iface.setAggrDate(lastDownloadDate);
647
				}
648
			}
649
			final String lastAggregationTotal = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_aggregation_total']");
650
			if (StringUtils.isEmpty(lastAggregationTotal)) {
651
				final String lastDownloadTotal = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_download_total']");
652
				if (StringUtils.isEmpty(lastDownloadTotal)) {
653
					iface.setAggrTotal(0);
654
				} else {
655
					iface.setAggrTotal(NumberUtils.toInt(lastDownloadTotal, 0));
656
				}
657
			} else {
658
				iface.setAggrTotal(NumberUtils.toInt(lastAggregationTotal, 0));
659
			}
660
		} catch (final Exception e) {
661
			log.error(e);
662
		}
663
		return iface;
664
	}
665

    
666
	private String obtainProfile(final String dsId) throws DatasourceManagerServiceException {
667
		try {
668
			return dsId.startsWith("entity/datasource")
669
					? is.getProfile(dsId)
670
					: is.find("collection('/db/DRIVER/entity/datasource')/*[.//DATASOURCE_ORIGINAL_ID='" + dsId + "']").get(0);
671
		} catch (final Throwable e) {
672
			log.error("Error accessing profile: " + dsId, e);
673
			throw new DatasourceManagerServiceException("Error accessing profile " + dsId, e);
674
		}
675
	}
676

    
677
}
(6-6/7)