Project

General

Profile

1
package eu.dnetlib.enabling.datasources;
2

    
3
import java.io.StringReader;
4
import java.text.ParseException;
5
import java.util.*;
6
import java.util.stream.Collectors;
7

    
8
import com.google.common.collect.Sets;
9
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
10
import eu.dnetlib.enabling.tools.AbstractBaseService;
11
import eu.dnetlib.rmi.datasource.*;
12
import eu.dnetlib.rmi.enabling.*;
13
import org.antlr.stringtemplate.StringTemplate;
14
import org.apache.commons.io.IOUtils;
15
import org.apache.commons.lang3.StringEscapeUtils;
16
import org.apache.commons.lang3.StringUtils;
17
import org.apache.commons.lang3.math.NumberUtils;
18
import org.apache.commons.logging.Log;
19
import org.apache.commons.logging.LogFactory;
20
import org.dom4j.Document;
21
import org.dom4j.Element;
22
import org.dom4j.Node;
23
import org.dom4j.io.SAXReader;
24
import org.quartz.CronExpression;
25
import org.springframework.beans.factory.annotation.Autowired;
26
import org.springframework.beans.factory.annotation.Required;
27
import org.springframework.core.io.ClassPathResource;
28

    
29
public class DatasourceManagerServiceImpl extends AbstractBaseService implements DatasourceManagerService {
30

    
31
	private static final Log log = LogFactory.getLog(DatasourceManagerServiceImpl.class);
32

    
33
	private static final String REPOSITORY_RESOURCE_TYPE = "RepositoryServiceResourceType";
34

    
35
	private List<XmlBrowsableField> browsableFields;
36

    
37
	private ClassPathResource findReposQueryTmpl = new ClassPathResource("/eu/dnetlib/enabling/datasources/templates/findRepos.xquery.st");
38

    
39
	private ClassPathResource browseRepoApisQueryTmpl = new ClassPathResource("/eu/dnetlib/enabling/datasources/templates/browseRepoApis.xquery.st");
40
	private ClassPathResource findRepoApisQueryTmpl = new ClassPathResource("/eu/dnetlib/enabling/datasources/templates/findRepoApis.xquery.st");
41
	private ClassPathResource findReposMapQuery = new ClassPathResource("/eu/dnetlib/enabling/datasources/templates/findReposMap.xquery");
42
	private ClassPathResource simpleFindReposQueryTmpl = new ClassPathResource("/eu/dnetlib/enabling/datasources/templates/simpleFindRepos.xquery.st");
43

    
44
	@Autowired
45
	private UniqueServiceLocator serviceLocator;
46

    
47
	private String fixDsId(final String dsId) throws DatasourceManagerServiceException {
48
		if (dsId.endsWith("_UGVuZGluZ1JlcG9zaXRvcnlSZXNvdXJjZXMvUmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZVR5cGU=")
49
				|| dsId.endsWith("_UmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZXMvUmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZVR5cGU=")) {
50
			return dsId;
51
		} else {
52
			try {
53
				return serviceLocator
54
						.getService(ISLookUpService.class)
55
						.getResourceProfileByQuery(
56
								"for $x in collection("
57
										+ "'/db/DRIVER/RepositoryServiceResources/RepositoryServiceResourceType',"
58
										+ "'/db/DRIVER/PendingRepositoryResources/RepositoryServiceResourceType') "
59
										+ "where $x//DATASOURCE_ORIGINAL_ID = '" + dsId + "' "
60
										+ "return $x//RESOURCE_IDENTIFIER/@value/string()");
61
			} catch (Exception e) {
62
				throw new DatasourceManagerServiceException("Invalid id: " + dsId, e);
63
			}
64
		}
65
	}
66

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

    
79
	@Override
80
	public boolean deleteDatasource(final String dsId) throws DatasourceManagerServiceException {
81
		return _deleteDatasource(fixDsId(dsId));
82
	}
83

    
84
	private boolean _deleteDatasource(final String dsId) throws DatasourceManagerServiceException {
85
		try {
86
			return serviceLocator.getService(ISRegistryService.class).deleteProfile(dsId);
87
		} catch (ISRegistryException e) {
88
			log.error("Error deleting profile " + dsId, e);
89
			throw new DatasourceManagerServiceException("Error deleting profile " + dsId, e);
90
		}
91
	}
92

    
93
	@Override
94
	public DatasourceDesc getDatasource(final String dsId) throws DatasourceManagerServiceException {
95
		return _getDatasource(fixDsId(dsId));
96
	}
97

    
98
	private DatasourceDesc _getDatasource(final String dsId) throws DatasourceManagerServiceException {
99
		try {
100
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
101
			return ProfileToDatasourceDesc.convert(profile);
102
		} catch (Exception e) {
103
			log.error("Error accessing profile " + dsId, e);
104
			throw new DatasourceManagerServiceException("Error accessing profile " + dsId, e);
105
		}
106
	}
107

    
108
	@Override
109
	public List<DatasourceDesc> listAllDatasources() throws DatasourceManagerServiceException {
110
		return listDatasourcesUsingFilter(null, null, null, null);
111
	}
112

    
113
	@Override
114
	public List<DatasourceDesc> listDatasourcesUsingFilter(final String compliance,
115
			final String contentDescription,
116
			final String iisProcessingWorkflow,
117
			final String collectedFrom)
118
			throws DatasourceManagerServiceException {
119
		try {
120
			final StringTemplate st = new StringTemplate();
121
			st.setTemplate(IOUtils.toString(findReposQueryTmpl.getInputStream()));
122

    
123
			final Map<String, String> conds = new HashMap<>();
124

    
125
			if (StringUtils.isNotBlank(compliance)) {
126
				conds.put("//INTERFACE/@compliance", compliance);
127
			}
128
			if (StringUtils.isNotBlank(contentDescription)) {
129
				conds.put("//INTERFACE/@contentDescription", contentDescription);
130
			}
131
			if (StringUtils.isNotBlank(iisProcessingWorkflow)) {
132
				// NOT USED
133
			}
134
			if (StringUtils.isNotBlank(collectedFrom)) {
135
				// NOT USED
136
			}
137

    
138
			if (!conds.isEmpty()) {
139
				st.setAttribute("conds", conds);
140
			}
141

    
142
			final List<String> list = serviceLocator.getService(ISLookUpService.class).quickSearchProfile(st.toString());
143

    
144
			return list.stream().map(new ProfileToDatasourceDesc()).collect(Collectors.toList());
145
		} catch (Exception e) {
146
			log.error("Error listing datasources", e);
147
			throw new DatasourceManagerServiceException("Error listing datasources", e);
148
		}
149
	}
150

    
151
	@Override
152
	public boolean updateLevelOfCompliance(final String dsId, final String ifaceId, final String level) throws DatasourceManagerServiceException {
153
		return _updateLevelOfCompliance(fixDsId(dsId), ifaceId, level);
154
	}
155

    
156
	private boolean _updateLevelOfCompliance(final String dsId, final String ifaceId, final String level) throws DatasourceManagerServiceException {
157
		try {
158
			return serviceLocator.getService(ISRegistryService.class)
159
					.updateProfileNode(dsId, "//INTERFACE[@id = '" + ifaceId + "']/@compliance", "'" + level + "'");
160
		} catch (Exception e) {
161
			log.error("Error updating profile: " + dsId, e);
162
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
163
		}
164
	}
165

    
166
	@Override
167
	public boolean updateBaseUrl(final String dsId, final String ifaceId, final String baseUrl) throws DatasourceManagerServiceException {
168
		return _updateBaseUrl(fixDsId(dsId), ifaceId, baseUrl);
169
	}
170

    
171
	private boolean _updateBaseUrl(final String dsId, final String ifaceId, final String baseUrl) throws DatasourceManagerServiceException {
172
		try {
173
			return serviceLocator.getService(ISRegistryService.class)
174
					.updateProfileNode(dsId, "//INTERFACE[@id = '" + ifaceId + "']/BASE_URL", "<BASE_URL>" + baseUrl + "</BASE_URL>");
175
		} catch (Exception e) {
176
			log.error("Error updating profile: " + dsId, e);
177
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
178
		}
179
	}
180

    
181
	@Override
182
	public boolean updateActivationStatus(final String dsId, final String ifaceId, final boolean active) throws DatasourceManagerServiceException {
183
		return _updateActivationStatus(fixDsId(dsId), ifaceId, active);
184
	}
185

    
186
	private boolean _updateActivationStatus(final String dsId, final String ifaceId, final boolean active) throws DatasourceManagerServiceException {
187
		try {
188
			return serviceLocator.getService(ISRegistryService.class)
189
					.updateProfileNode(dsId, "//INTERFACE[@id = '" + ifaceId + "']/@active", "'" + active + "'");
190
		} catch (Exception e) {
191
			log.error("Error updating profile: " + dsId, e);
192
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
193
		}
194
	}
195

    
196
	@Override
197
	public boolean updateContentDescription(final String dsId, final String ifaceId, final String desc) throws DatasourceManagerServiceException {
198
		return _updateContentDescription(fixDsId(dsId), ifaceId, desc);
199
	}
200

    
201
	private boolean _updateContentDescription(final String dsId, final String ifaceId, final String desc) throws DatasourceManagerServiceException {
202
		try {
203
			return serviceLocator.getService(ISRegistryService.class)
204
					.updateProfileNode(dsId, "//INTERFACE[@id = '" + ifaceId + "']/@contentDescription", "'" + desc + "'");
205
		} catch (Exception e) {
206
			log.error("Error updating profile: " + dsId, e);
207
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
208
		}
209
	}
210

    
211
	@Override
212
	public boolean setIisProcessingWorkflow(final String dsId, final String ifaceId, final String wf) throws DatasourceManagerServiceException {
213
		throw new DatasourceManagerServiceException("NOT IMPLEMENTED");
214
	}
215

    
216
	@Override
217
	public boolean updateExtraField(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
218
			throws DatasourceManagerServiceException {
219
		return _updateExtraField(fixDsId(dsId), ifaceId, field, value, preserveOriginal);
220
	}
221

    
222
	private boolean _updateExtraField(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
223
			throws DatasourceManagerServiceException {
224
		try {
225
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
226
			final Document doc = new SAXReader().read(new StringReader(profile));
227

    
228
			final Node ifcNode = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
229
			final Node node = ifcNode.selectSingleNode("./INTERFACE_EXTRA_FIELD[@name = '" + field + "']");
230
			if (node != null) {
231
				node.setText(value);
232
			} else {
233
				final Element e = ((Element) ifcNode).addElement("INTERFACE_EXTRA_FIELD");
234
				e.addAttribute("name", field);
235
				e.setText(value);
236
			}
237
			return serviceLocator.getService(ISRegistryService.class).updateProfile(dsId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
238
		} catch (Exception e) {
239
			log.error("Error updating profile: " + dsId, e);
240
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
241
		}
242
	}
243

    
244
	@Override
245
	public boolean updateAccessParam(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
246
			throws DatasourceManagerServiceException {
247
		return _updateAccessParam(fixDsId(dsId), ifaceId, field, value, preserveOriginal);
248
	}
249

    
250
	private boolean _updateAccessParam(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
251
			throws DatasourceManagerServiceException {
252
		try {
253
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
254
			final Document doc = new SAXReader().read(new StringReader(profile));
255

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

    
259
			return serviceLocator.getService(ISRegistryService.class).updateProfile(dsId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
260
		} catch (Exception e) {
261
			log.error("Error updating profile: " + dsId, e);
262
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
263
		}
264
	}
265

    
266
	@Override
267
	public boolean deleteAccessParamOrExtraField(final String dsId, final String ifaceId, final String field) throws DatasourceManagerServiceException {
268
		return _deleteAccessParamOrExtraField(fixDsId(dsId), ifaceId, field);
269
	}
270

    
271
	private boolean _deleteAccessParamOrExtraField(final String dsId, final String ifaceId, final String field) throws DatasourceManagerServiceException {
272
		try {
273
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
274
			final Document doc = new SAXReader().read(new StringReader(profile));
275

    
276
			final Node ef = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']/INTERFACE_EXTRA_FIELD[@name = '" + field + "']");
277
			if (ef != null) {
278
				ef.detach();
279
			}
280
			final Node ap = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']/ACCESS_PROTOCOL/@" + field);
281
			if (ap != null) {
282
				ap.detach();
283

    
284
			}
285
			return serviceLocator.getService(ISRegistryService.class).updateProfile(dsId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
286
		} catch (Exception e) {
287
			log.error("Error updating profile: " + dsId, e);
288
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
289
		}
290
	}
291

    
292
	@Override
293
	public boolean addInterface(final String dsId, final IfaceDesc iface) throws DatasourceManagerServiceException {
294
		return _addInterface(fixDsId(dsId), iface);
295
	}
296

    
297
	private boolean _addInterface(final String dsId, final IfaceDesc iface) throws DatasourceManagerServiceException {
298
		try {
299
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
300
			final Document doc = new SAXReader().read(new StringReader(profile));
301

    
302
			final Node node = doc.selectSingleNode("//INTERFACE[@id = '" + iface.getId() + "']");
303
			if (node != null) {
304
				node.detach();
305
			}
306

    
307
			((Element) doc.selectSingleNode("//INTERFACES")).add(IfaceDescToNode.convert(iface));
308

    
309
			return serviceLocator.getService(ISRegistryService.class).updateProfile(dsId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
310
		} catch (Exception e) {
311
			log.error("Error updating profile: " + dsId, e);
312
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
313
		}
314
	}
315

    
316
	@Override
317
	public boolean deleteInterface(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
318
		return _deleteInterface(fixDsId(dsId), ifaceId);
319
	}
320

    
321
	private boolean _deleteInterface(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
322
		try {
323
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
324
			final Document doc = new SAXReader().read(new StringReader(profile));
325

    
326
			final Node node = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
327
			if (node != null) {
328
				node.detach();
329
			}
330

    
331
			return serviceLocator.getService(ISRegistryService.class).updateProfile(dsId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
332
		} catch (Exception e) {
333
			log.error("Error updating profile: " + dsId, e);
334
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
335
		}
336
	}
337

    
338
	@Override
339
	public boolean updateSQL(final String dsId, final String sql, final boolean delete) throws DatasourceManagerServiceException {
340
		throw new DatasourceManagerServiceException("NOT IMPLEMENTED");
341
	}
342

    
343
	@Override
344
	public Date findNextScheduledExecution(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
345
		return _findNextScheduledExecution(fixDsId(dsId), ifaceId);
346
	}
347

    
348
	private Date _findNextScheduledExecution(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
349
		final String xquery = "/*[.//DATAPROVIDER/@interface='" + ifaceId + "' and .//SCHEDULING/@enabled='true']//CRON/text()";
350
		try {
351
			final String cronExpression = serviceLocator.getService(ISLookUpService.class).getResourceProfileByQuery(xquery);
352
			final CronExpression cron = new CronExpression(cronExpression);
353
			return cron.getNextValidTimeAfter(new Date());
354
		} catch (ISLookUpDocumentNotFoundException e) {
355
			// When the value is not found a null value must be returned
356
			return null;
357
		} catch (ISLookUpException e) {
358
			log.error("Error in xquery: " + xquery, e);
359
			throw new DatasourceManagerServiceException("Error in xquery: " + xquery, e);
360
		} catch (ParseException e) {
361
			log.error("Error parsing cron expression", e);
362
			throw new DatasourceManagerServiceException("Error parsing cron expression", e);
363
		}
364
	}
365

    
366
	@Override
367
	public boolean bulkUpdateApiExtraFields(final String repoId, final String ifaceId, final Map<String, String> fields)
368
			throws DatasourceManagerServiceException {
369
		try {
370
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(repoId);
371

    
372
			final SAXReader reader = new SAXReader();
373
			final Document doc = reader.read(new StringReader(profile));
374

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

    
378
				while (iface.selectNodes("./INTERFACE_EXTRA_FIELD").size() > 0) {
379
					iface.selectSingleNode("./INTERFACE_EXTRA_FIELD").detach();
380
				}
381

    
382
				fields.entrySet().forEach(e -> {
383
					if (e.getValue() != null && !e.getValue().isEmpty()) {
384
						final Element field = iface.addElement("INTERFACE_EXTRA_FIELD");
385
						field.addAttribute("name", e.getKey());
386
						field.addText(e.getValue());
387
					}
388
				});
389
				serviceLocator.getService(ISRegistryService.class).updateProfile(repoId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
390
			} else {
391
				log.error("Invalid interface: " + ifaceId);
392
				throw new DatasourceManagerServiceException("Missing interface: " + ifaceId);
393
			}
394
		} catch (Exception e) {
395
			log.error("Error updating API of profile: " + repoId);
396
			throw new DatasourceManagerServiceException("Error updating API of profile: " + repoId, e);
397
		}
398
		return true;
399

    
400
	}
401

    
402
	@Override
403
	public boolean bulkUpdateApiAccessParams(final String dsId, final String ifaceId, final Map<String, String> params)
404
			throws DatasourceManagerServiceException {
405
		return _bulkUpdateApiAccessParams(fixDsId(dsId), ifaceId, params);
406
	}
407

    
408
	private boolean _bulkUpdateApiAccessParams(final String repoId, final String ifaceId, final Map<String, String> params)
409
			throws DatasourceManagerServiceException {
410
		try {
411
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(repoId);
412

    
413
			final SAXReader reader = new SAXReader();
414
			final Document doc = reader.read(new StringReader(profile));
415

    
416
			final Element accessNode = (Element) doc.selectSingleNode("//INTERFACE[@id='" + ifaceId + "']/ACCESS_PROTOCOL");
417
			if (accessNode != null) {
418
				while (accessNode.attributes().size() > 0) {
419
					accessNode.selectSingleNode("@*").detach();
420
				}
421
				for (Map.Entry<String, String> e : params.entrySet()) {
422
					if (e.getValue() != null && !e.getValue().isEmpty()) {
423
						if (e.getKey().equalsIgnoreCase("baseUrl")) {
424
							doc.selectSingleNode("//INTERFACE[@id='" + ifaceId + "']/BASE_URL").setText(e.getValue());
425
						} else {
426
							accessNode.addAttribute(e.getKey(), e.getValue());
427
						}
428
					}
429
				}
430
				serviceLocator.getService(ISRegistryService.class).updateProfile(repoId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
431
			} else {
432
				log.error("Invalid interface: " + ifaceId);
433
				throw new DatasourceManagerServiceException("Missing interface: " + ifaceId);
434
			}
435
		} catch (Exception e) {
436
			log.error("Error updating API of profile: " + repoId);
437
			throw new DatasourceManagerServiceException("Error updating API of profile: " + repoId, e);
438
		}
439
		return true;
440
	}
441

    
442
	@Override
443
	public boolean overrideCompliance(final String dsId, final String ifaceId, final String level) throws DatasourceManagerServiceException {
444
		return _overrideCompliance(fixDsId(dsId), ifaceId, level);
445
	}
446

    
447
	private boolean _overrideCompliance(final String repoId, final String ifaceId, final String compliance) throws DatasourceManagerServiceException {
448
		try {
449
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(repoId);
450

    
451
			final SAXReader reader = new SAXReader();
452
			final Document doc = reader.read(new StringReader(profile));
453

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

    
458
				if (!StringUtils.isEmpty(compliance)) {
459
					fields.put(DatasourceConstants.OVERRIDING_COMPLIANCE_FIELD, compliance);
460
				}
461

    
462
				while (iface.selectNodes("./INTERFACE_EXTRA_FIELD").size() > 0) {
463
					final Node node = iface.selectSingleNode("./INTERFACE_EXTRA_FIELD");
464
					final String name = node.valueOf("@name");
465

    
466
					if (!name.equals(DatasourceConstants.OVERRIDING_COMPLIANCE_FIELD)) {
467
						fields.put(node.valueOf("@name"), node.getText());
468
					}
469
					node.detach();
470
				}
471

    
472
				for (Map.Entry<String, String> e : fields.entrySet()) {
473
					if (e.getValue() != null && !e.getValue().isEmpty()) {
474
						final Element field = iface.addElement("INTERFACE_EXTRA_FIELD");
475
						field.addAttribute("name", e.getKey());
476
						field.addText(e.getValue());
477
					}
478
				}
479
				serviceLocator.getService(ISRegistryService.class).updateProfile(repoId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
480
			} else {
481
				log.error("Invalid interface: " + ifaceId);
482
				throw new DatasourceManagerServiceException("Missing interface: " + ifaceId);
483
			}
484
		} catch (Exception e) {
485
			log.error("Error updating API of profile: " + repoId);
486
			throw new DatasourceManagerServiceException("Error updating API of profile: " + repoId, e);
487
		}
488

    
489
		return true;
490
	}
491

    
492
	@Override
493
	public List<BrowsableField> listBrowsableFields() throws DatasourceManagerServiceException {
494
		return getBrowsableFields().stream().map(f -> new BrowsableField(f.getId(), f.getLabel())).collect(Collectors.toList());
495
	}
496

    
497
	@Override
498
	public List<BrowseTerm> browseField(final String f) throws DatasourceManagerServiceException {
499

    
500
		final List<BrowseTerm> list = new ArrayList<>();
501

    
502
		try {
503
			final XmlBrowsableField field = findBrowseField(f);
504
			if (field != null) {
505
				final StringTemplate st = new StringTemplate(IOUtils.toString(browseRepoApisQueryTmpl.getInputStream()));
506
				st.setAttribute("xpath", field.getXpath());
507

    
508
				final Map<String, String> terms = fetchVocabularyTerms(field.getVocabulary());
509

    
510
				for (String s : serviceLocator.getService(ISLookUpService.class).quickSearchProfile(st.toString())) {
511
					final String[] arr = s.split("@-@-@");
512
					final String id = arr[0].trim();
513
					final int count = NumberUtils.toInt(arr[1].trim(), 0);
514
					list.add(new BrowseTerm(id, findLabel(id, terms), count));
515
				}
516
			}
517
		} catch (Exception e) {
518
			log.error("Error browsing field " + f, e);
519
		}
520

    
521
		return list;
522
	}
523

    
524
	private String findLabel(final String code, final Map<String, String> terms) {
525
		return terms.containsKey(code) ? terms.get(code) : code;
526
	}
527

    
528
	public Map<String, String> fetchVocabularyTerms(final String voc) throws ISLookUpException {
529
		final String xquery = "for $x in collection('/db/DRIVER/VocabularyDSResources/VocabularyDSResourceType')[.//VOCABULARY_NAME/@code = '"
530
				+ voc.trim() + "']//TERM return concat($x/@code, ' @@@ ', $x/@english_name)";
531

    
532
		final Map<String, String> map = new HashMap<>();
533
		for (String s : serviceLocator.getService(ISLookUpService.class).quickSearchProfile(xquery)) {
534
			final String[] arr = s.split("@@@");
535
			map.put(arr[0].trim(), arr[1].trim());
536
		}
537
		return map;
538
	}
539

    
540
	private XmlBrowsableField findBrowseField(final String id) {
541
		for (XmlBrowsableField f : getBrowsableFields()) {
542
			if (f.getId().equals(id)) { return f; }
543
		}
544
		return null;
545
	}
546

    
547
	@Override
548
	public List<SearchInterfacesEntry> searchInterface(final String field, final String value) throws DatasourceManagerServiceException {
549
		try {
550

    
551
			final StringTemplate st = new StringTemplate();
552
			st.setTemplate(IOUtils.toString(findRepoApisQueryTmpl.getInputStream()));
553

    
554
			if (field.equalsIgnoreCase("__search__")) {
555
				st.setAttribute("cond", "contains(../..//(*|@*)/lower-case(.), '" + StringEscapeUtils.escapeXml11(value.toLowerCase()) + "')");
556
			} else {
557
				final XmlBrowsableField f = findBrowseField(field);
558
				if (f != null) {
559
					st.setAttribute("cond", f.getXpath() + "='" + StringEscapeUtils.escapeXml11(value) + "'");
560
				} else {
561
					return new ArrayList<>();
562
				}
563
			}
564

    
565
			final String query = st.toString();
566

    
567
			final SAXReader reader = new SAXReader();
568

    
569
			return serviceLocator.getService(ISLookUpService.class).quickSearchProfile(query).stream()
570
					.map(it -> convertSearchInterface(it, reader)).collect(Collectors.toList());
571

    
572
		} catch (Exception e) {
573
			log.error("Error searching field " + field + " - value: " + value, e);
574
		}
575
		return new ArrayList<>();
576
	}
577

    
578
	private SearchInterfacesEntry convertSearchInterface(final String s, final SAXReader reader) {
579
		final SearchInterfacesEntry iface = new SearchInterfacesEntry();
580
		try {
581
			final Document doc = reader.read(new StringReader(s));
582
			final String country = doc.valueOf("//REPO/@country");
583

    
584
			iface.setRepoId(doc.valueOf("//REPO/@id"));
585
			iface.setRepoCountry(StringUtils.isEmpty(country) ? "-" : country.toUpperCase());
586
			iface.setRepoName(doc.valueOf("//REPO/@name"));
587
			iface.setRepoPrefix(doc.valueOf("//REPO/@prefix"));
588

    
589
			final Node ifcNode = doc.selectSingleNode("//INTERFACE");
590

    
591
			iface.setId(ifcNode.valueOf("./@id"));
592
			iface.setActive(Boolean.valueOf(ifcNode.valueOf("./@active")));
593
			iface.setProtocol(ifcNode.valueOf("./ACCESS_PROTOCOL/text()"));
594

    
595
			final String overCompliance = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='overriding_compliance']");
596
			if (StringUtils.isEmpty(overCompliance)) {
597
				iface.setCompliance(ifcNode.valueOf("@compliance"));
598
			} else {
599
				iface.setCompliance(overCompliance);
600
			}
601

    
602
			final String lastAggregationDate = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_aggregation_date']");
603
			if (!StringUtils.isEmpty(lastAggregationDate)) {
604
				iface.setAggrDate(lastAggregationDate);
605
			} else {
606
				final String lastDownloadDate = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_download_date']");
607
				if (!StringUtils.isEmpty(lastDownloadDate)) {
608
					iface.setAggrDate(lastDownloadDate);
609
				}
610
			}
611
			final String lastAggregationTotal = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_aggregation_total']");
612
			if (StringUtils.isEmpty(lastAggregationTotal)) {
613
				final String lastDownloadTotal = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_download_total']");
614
				if (StringUtils.isEmpty(lastDownloadTotal)) {
615
					iface.setAggrTotal(0);
616
				} else {
617
					iface.setAggrTotal(NumberUtils.toInt(lastDownloadTotal, 0));
618
				}
619
			} else {
620
				iface.setAggrTotal(NumberUtils.toInt(lastAggregationTotal, 0));
621
			}
622
		} catch (Exception e) {
623
			log.error(e);
624
		}
625
		return iface;
626
	}
627

    
628
	private RepositoryMapEntry convertRepositoryMapEntry(final String s, final SAXReader reader) {
629

    
630
		final RepositoryMapEntry r = new RepositoryMapEntry();
631

    
632
		try {
633
			final Document doc = reader.read(new StringReader(s));
634
			r.setId(doc.valueOf("//dsId"));
635
			r.setName(doc.valueOf("//name"));
636
			r.setLat(Float.parseFloat(doc.valueOf("//lat")));
637
			r.setLng(Float.parseFloat(doc.valueOf("//lng")));
638
		} catch (Exception e) {
639
			log.error(e);
640

    
641
		}
642
		return r;
643

    
644
	}
645

    
646
	@Override
647
	public List<RepositoryMapEntry> getRepositoryMap() throws DatasourceManagerServiceException {
648
		try {
649
			final SAXReader reader = new SAXReader();
650

    
651
			final String query = IOUtils.toString(findReposMapQuery.getInputStream());
652
			return serviceLocator.getService(ISLookUpService.class).quickSearchProfile(query)
653
					.stream()
654
					.map(it -> convertRepositoryMapEntry(it, reader))
655
					.collect(Collectors.toList());
656

    
657
		} catch (Exception e) {
658
			log.error("Error obtaing repo map entries", e);
659
		}
660
		return new ArrayList<>();
661
	}
662

    
663
	private List<XmlBrowsableField> getBrowsableFields() {
664
		return browsableFields;
665
	}
666

    
667
	@Required
668
	public void setBrowsableFields(final List<XmlBrowsableField> browsableFields) {
669
		this.browsableFields = browsableFields;
670
	}
671

    
672
	@Override
673
	public List<SimpleDatasourceDesc> simpleListDatasourcesByType(final String type) throws DatasourceManagerServiceException {
674
		try {
675
			final List<SimpleDatasourceDesc> list = new ArrayList<>();
676

    
677
			final StringTemplate st = new StringTemplate(IOUtils.toString(simpleFindReposQueryTmpl.getInputStream()));
678
			st.setAttribute("type", type);
679

    
680
			for (String s : serviceLocator.getService(ISLookUpService.class).quickSearchProfile(st.toString())) {
681
				final SimpleDatasourceDesc r = new SimpleDatasourceDesc();
682
				final String[] arr = s.split("@=@");
683
				r.setId(arr[0].trim());
684
				r.setName(arr[1].trim());
685
				r.setOrigId(arr[2].trim());
686
				r.setApis(Sets.newHashSet(arr[3].replaceAll("\\s", "").split(",")));
687
				r.setValid("true".equals(arr[4].trim()));
688
				r.setTypology(type);
689
				list.add(r);
690
			}
691

    
692
			Collections.sort(list);
693

    
694
			return list;
695
		} catch (Exception e) {
696
			log.error("Error listing repos", e);
697
		}
698
		return new ArrayList<>();
699
	}
700

    
701
}
(2-2/5)