Project

General

Profile

1
package eu.dnetlib.enabling.datasources;
2

    
3
import java.io.StringReader;
4
import java.text.ParseException;
5
import java.util.Collections;
6
import java.util.Date;
7
import java.util.List;
8
import java.util.Map;
9

    
10
import javax.annotation.Resource;
11

    
12
import org.antlr.stringtemplate.StringTemplate;
13
import org.apache.commons.io.IOUtils;
14
import org.apache.commons.lang3.StringEscapeUtils;
15
import org.apache.commons.lang3.StringUtils;
16
import org.apache.commons.lang3.math.NumberUtils;
17
import org.apache.commons.logging.Log;
18
import org.apache.commons.logging.LogFactory;
19
import org.dom4j.Document;
20
import org.dom4j.Element;
21
import org.dom4j.Node;
22
import org.dom4j.io.SAXReader;
23
import org.quartz.CronExpression;
24
import org.springframework.beans.factory.annotation.Required;
25
import org.springframework.core.io.ClassPathResource;
26

    
27
import com.google.common.base.Function;
28
import com.google.common.collect.Lists;
29
import com.google.common.collect.Maps;
30
import com.google.common.collect.Sets;
31

    
32
import eu.dnetlib.enabling.datasources.rmi.BrowsableField;
33
import eu.dnetlib.enabling.datasources.rmi.BrowseTerm;
34
import eu.dnetlib.enabling.datasources.rmi.DatasourceConstants;
35
import eu.dnetlib.enabling.datasources.rmi.DatasourceDesc;
36
import eu.dnetlib.enabling.datasources.rmi.DatasourceManagerService;
37
import eu.dnetlib.enabling.datasources.rmi.DatasourceManagerServiceException;
38
import eu.dnetlib.enabling.datasources.rmi.IfaceDesc;
39
import eu.dnetlib.enabling.datasources.rmi.RepositoryMapEntry;
40
import eu.dnetlib.enabling.datasources.rmi.SearchInterfacesEntry;
41
import eu.dnetlib.enabling.datasources.rmi.SimpleDatasourceDesc;
42
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException;
43
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
44
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
45
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
46
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
47
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
48
import eu.dnetlib.enabling.tools.AbstractBaseService;
49

    
50
public class DatasourceManagerServiceImpl extends AbstractBaseService implements DatasourceManagerService {
51

    
52
	private static final Log log = LogFactory.getLog(DatasourceManagerServiceImpl.class);
53

    
54
	private static final String REPOSITORY_RESOURCE_TYPE = "RepositoryServiceResourceType";
55

    
56
	private List<XmlBrowsableField> browsableFields;
57

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

    
60
	private ClassPathResource browseRepoApisQueryTmpl = new ClassPathResource("/eu/dnetlib/enabling/datasources/templates/browseRepoApis.xquery.st");
61
	private ClassPathResource findRepoApisQueryTmpl = new ClassPathResource("/eu/dnetlib/enabling/datasources/templates/findRepoApis.xquery.st");
62
	private ClassPathResource findReposMapQuery = new ClassPathResource("/eu/dnetlib/enabling/datasources/templates/findReposMap.xquery");
63
	private ClassPathResource simpleFindReposQueryTmpl = new ClassPathResource("/eu/dnetlib/enabling/datasources/templates/simpleFindRepos.xquery.st");
64

    
65
	@Resource
66
	private UniqueServiceLocator serviceLocator;
67

    
68
	private String environment;
69

    
70
	private String fixDsId(final String dsId) throws DatasourceManagerServiceException {
71
		if (dsId.endsWith("_UGVuZGluZ1JlcG9zaXRvcnlSZXNvdXJjZXMvUmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZVR5cGU=")
72
				|| dsId.endsWith("_UmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZXMvUmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZVR5cGU=")) {
73
			return dsId;
74
		} else {
75
			try {
76
				return serviceLocator
77
						.getService(ISLookUpService.class)
78
						.getResourceProfileByQuery(
79
								"for $x in collection("
80
										+ "'/db/DRIVER/RepositoryServiceResources/RepositoryServiceResourceType',"
81
										+ "'/db/DRIVER/PendingRepositoryResources/RepositoryServiceResourceType') "
82
										+ "where $x//DATASOURCE_ORIGINAL_ID = '" + dsId + "' "
83
										+ "return $x//RESOURCE_IDENTIFIER/@value/string()");
84
			} catch (Exception e) {
85
				throw new DatasourceManagerServiceException("Invalid id: " + dsId, e);
86
			}
87
		}
88
	}
89

    
90
	@Override
91
	public boolean addDatasource(final DatasourceDesc ds) throws DatasourceManagerServiceException {
92
		try {
93
			final String profile = DatasourceDescToProfile.convert(ds, environment);
94
			serviceLocator.getService(ISRegistryService.class).registerProfile(profile);
95
			return true;
96
		} catch (Exception e) {
97
			log.error("Error registering profile", e);
98
			throw new DatasourceManagerServiceException("Error registering profile", e);
99
		}
100
	}
101

    
102
	@Override
103
	public boolean deleteDatasource(final String dsId) throws DatasourceManagerServiceException {
104
		return _deleteDatasource(fixDsId(dsId));
105
	}
106

    
107
	private boolean _deleteDatasource(final String dsId) throws DatasourceManagerServiceException {
108
		try {
109
			return serviceLocator.getService(ISRegistryService.class).deleteProfile(dsId);
110
		} catch (ISRegistryException e) {
111
			log.error("Error deleting profile " + dsId, e);
112
			throw new DatasourceManagerServiceException("Error deleting profile " + dsId, e);
113
		}
114
	}
115

    
116
	@Override
117
	public DatasourceDesc getDatasource(final String dsId) throws DatasourceManagerServiceException {
118
		return _getDatasource(fixDsId(dsId));
119
	}
120

    
121
	private DatasourceDesc _getDatasource(final String dsId) throws DatasourceManagerServiceException {
122
		try {
123
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
124
			return ProfileToDatasourceDesc.convert(profile);
125
		} catch (Exception e) {
126
			log.error("Error accessing profile " + dsId, e);
127
			throw new DatasourceManagerServiceException("Error accessing profile " + dsId, e);
128
		}
129
	}
130

    
131
	@Override
132
	public List<DatasourceDesc> listAllDatasources() throws DatasourceManagerServiceException {
133
		return listDatasourcesUsingFilter(null, null, null, null);
134
	}
135

    
136
	@Override
137
	public List<DatasourceDesc> listDatasourcesUsingFilter(final String compliance,
138
			final String contentDescription,
139
			final String iisProcessingWorkflow,
140
			final String collectedFrom)
141
			throws DatasourceManagerServiceException {
142
		try {
143
			final StringTemplate st = new StringTemplate();
144
			st.setTemplate(IOUtils.toString(findReposQueryTmpl.getInputStream()));
145

    
146
			final Map<String, String> conds = Maps.newHashMap();
147

    
148
			if (StringUtils.isNotBlank(compliance)) {
149
				conds.put("//INTERFACE/@compliance", compliance);
150
			}
151
			if (StringUtils.isNotBlank(contentDescription)) {
152
				conds.put("//INTERFACE/@contentDescription", contentDescription);
153
			}
154
			if (StringUtils.isNotBlank(iisProcessingWorkflow)) {
155
				// NOT USED
156
			}
157
			if (StringUtils.isNotBlank(collectedFrom)) {
158
				// NOT USED
159
			}
160

    
161
			if (!conds.isEmpty()) {
162
				st.setAttribute("conds", conds);
163
			}
164

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

    
167
			return Lists.transform(list, new ProfileToDatasourceDesc());
168
		} catch (Exception e) {
169
			log.error("Error listing datasources", e);
170
			throw new DatasourceManagerServiceException("Error listing datasources", e);
171
		}
172
	}
173

    
174
	@Override
175
	public boolean updateLevelOfCompliance(final String dsId, final String ifaceId, final String level) throws DatasourceManagerServiceException {
176
		return _updateLevelOfCompliance(fixDsId(dsId), ifaceId, level);
177
	}
178

    
179
	private boolean _updateLevelOfCompliance(final String dsId, final String ifaceId, final String level) throws DatasourceManagerServiceException {
180
		try {
181
			return serviceLocator.getService(ISRegistryService.class)
182
					.updateProfileNode(dsId, "//INTERFACE[@id = '" + ifaceId + "']/@compliance", "'" + level + "'");
183
		} catch (Exception e) {
184
			log.error("Error updating profile: " + dsId, e);
185
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
186
		}
187
	}
188

    
189
	@Override
190
	public boolean updateBaseUrl(final String dsId, final String ifaceId, final String baseUrl) throws DatasourceManagerServiceException {
191
		return _updateBaseUrl(fixDsId(dsId), ifaceId, baseUrl);
192
	}
193

    
194
	private boolean _updateBaseUrl(final String dsId, final String ifaceId, final String baseUrl) throws DatasourceManagerServiceException {
195
		try {
196
			return serviceLocator.getService(ISRegistryService.class)
197
					.updateProfileNode(dsId, "//INTERFACE[@id = '" + ifaceId + "']/BASE_URL", "<BASE_URL>" + baseUrl + "</BASE_URL>");
198
		} catch (Exception e) {
199
			log.error("Error updating profile: " + dsId, e);
200
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
201
		}
202
	}
203

    
204
	@Override
205
	public boolean updateActivationStatus(final String dsId, final String ifaceId, final boolean active) throws DatasourceManagerServiceException {
206
		return _updateActivationStatus(fixDsId(dsId), ifaceId, active);
207
	}
208

    
209
	private boolean _updateActivationStatus(final String dsId, final String ifaceId, final boolean active) throws DatasourceManagerServiceException {
210
		try {
211
			return serviceLocator.getService(ISRegistryService.class)
212
					.updateProfileNode(dsId, "//INTERFACE[@id = '" + ifaceId + "']/@active", "'" + active + "'");
213
		} catch (Exception e) {
214
			log.error("Error updating profile: " + dsId, e);
215
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
216
		}
217
	}
218

    
219
	@Override
220
	public boolean updateContentDescription(final String dsId, final String ifaceId, final String desc) throws DatasourceManagerServiceException {
221
		return _updateContentDescription(fixDsId(dsId), ifaceId, desc);
222
	}
223

    
224
	private boolean _updateContentDescription(final String dsId, final String ifaceId, final String desc) throws DatasourceManagerServiceException {
225
		try {
226
			return serviceLocator.getService(ISRegistryService.class)
227
					.updateProfileNode(dsId, "//INTERFACE[@id = '" + ifaceId + "']/@contentDescription", "'" + desc + "'");
228
		} catch (Exception e) {
229
			log.error("Error updating profile: " + dsId, e);
230
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
231
		}
232
	}
233

    
234
	@Override
235
	public boolean setIisProcessingWorkflow(final String dsId, final String ifaceId, final String wf) throws DatasourceManagerServiceException {
236
		throw new DatasourceManagerServiceException("NOT IMPLEMENTED");
237
	}
238

    
239
	@Override
240
	public boolean updateExtraField(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
241
			throws DatasourceManagerServiceException {
242
		return _updateExtraField(fixDsId(dsId), ifaceId, field, value, preserveOriginal);
243
	}
244

    
245
	private boolean _updateExtraField(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
246
			throws DatasourceManagerServiceException {
247
		try {
248
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
249
			final Document doc = new SAXReader().read(new StringReader(profile));
250

    
251
			final Node ifcNode = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
252
			final Node node = ifcNode.selectSingleNode("./INTERFACE_EXTRA_FIELD[@name = '" + field + "']");
253
			if (node != null) {
254
				node.setText(value);
255
			} else {
256
				final Element e = ((Element) ifcNode).addElement("INTERFACE_EXTRA_FIELD");
257
				e.addAttribute("name", field);
258
				e.setText(value);
259
			}
260
			return serviceLocator.getService(ISRegistryService.class).updateProfile(dsId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
261
		} catch (Exception e) {
262
			log.error("Error updating profile: " + dsId, e);
263
			throw new DatasourceManagerServiceException("Error updating profile: " + dsId, e);
264
		}
265
	}
266

    
267
	@Override
268
	public boolean updateAccessParam(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
269
			throws DatasourceManagerServiceException {
270
		return _updateAccessParam(fixDsId(dsId), ifaceId, field, value, preserveOriginal);
271
	}
272

    
273
	private boolean _updateAccessParam(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal)
274
			throws DatasourceManagerServiceException {
275
		try {
276
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
277
			final Document doc = new SAXReader().read(new StringReader(profile));
278

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

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

    
289
	@Override
290
	public boolean deleteAccessParamOrExtraField(final String dsId, final String ifaceId, final String field) throws DatasourceManagerServiceException {
291
		return _deleteAccessParamOrExtraField(fixDsId(dsId), ifaceId, field);
292
	}
293

    
294
	private boolean _deleteAccessParamOrExtraField(final String dsId, final String ifaceId, final String field) throws DatasourceManagerServiceException {
295
		try {
296
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
297
			final Document doc = new SAXReader().read(new StringReader(profile));
298

    
299
			final Node ef = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']/INTERFACE_EXTRA_FIELD[@name = '" + field + "']");
300
			if (ef != null) {
301
				ef.detach();
302
			}
303
			final Node ap = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']/ACCESS_PROTOCOL/@" + field);
304
			if (ap != null) {
305
				ap.detach();
306

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

    
315
	@Override
316
	public boolean addInterface(final String dsId, final IfaceDesc iface) throws DatasourceManagerServiceException {
317
		iface.setRemovable(true);
318
		return _addInterface(fixDsId(dsId), iface);
319
	}
320

    
321
	private boolean _addInterface(final String dsId, final IfaceDesc iface) 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 = '" + iface.getId() + "']");
327
			if (node != null) {
328
				node.detach();
329
			}
330

    
331
			((Element) doc.selectSingleNode("//INTERFACES")).add(IfaceDescToNode.convert(iface));
332

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

    
340
	@Override
341
	public boolean deleteInterface(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
342
		return _deleteInterface(fixDsId(dsId), ifaceId);
343
	}
344

    
345
	private boolean _deleteInterface(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
346
		try {
347
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(dsId);
348
			final Document doc = new SAXReader().read(new StringReader(profile));
349

    
350
			final Node node = doc.selectSingleNode("//INTERFACE[@id = '" + ifaceId + "']");
351
			if (node != null) {
352
				node.detach();
353
			}
354

    
355
			return serviceLocator.getService(ISRegistryService.class).updateProfile(dsId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
356
		} catch (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 updateSQL(final String dsId, final String sql, final boolean delete) throws DatasourceManagerServiceException {
364
		throw new DatasourceManagerServiceException("NOT IMPLEMENTED");
365
	}
366

    
367
	@Override
368
	public Date findNextScheduledExecution(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
369
		return _findNextScheduledExecution(fixDsId(dsId), ifaceId);
370
	}
371

    
372
	private Date _findNextScheduledExecution(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
373
		final String xquery = "/*[.//DATAPROVIDER/@interface='" + ifaceId + "' and .//SCHEDULING/@enabled='true']//CRON/text()";
374
		try {
375
			final String cronExpression = serviceLocator.getService(ISLookUpService.class).getResourceProfileByQuery(xquery);
376
			final CronExpression cron = new CronExpression(cronExpression);
377
			return cron.getNextValidTimeAfter(new Date());
378
		} catch (ISLookUpDocumentNotFoundException e) {
379
			// When the value is not found a null value must be returned
380
			return null;
381
		} catch (ISLookUpException e) {
382
			log.error("Error in xquery: " + xquery, e);
383
			throw new DatasourceManagerServiceException("Error in xquery: " + xquery, e);
384
		} catch (ParseException e) {
385
			log.error("Error parsing cron expression", e);
386
			throw new DatasourceManagerServiceException("Error parsing cron expression", e);
387
		}
388
	}
389

    
390
	@Override
391
	public boolean bulkUpdateApiExtraFields(final String repoId, final String ifaceId, final Map<String, String> fields)
392
			throws DatasourceManagerServiceException {
393
		try {
394
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(repoId);
395

    
396
			final SAXReader reader = new SAXReader();
397
			final Document doc = reader.read(new StringReader(profile));
398

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

    
402
				while (iface.selectNodes("./INTERFACE_EXTRA_FIELD").size() > 0) {
403
					iface.selectSingleNode("./INTERFACE_EXTRA_FIELD").detach();
404
				}
405
				for (Map.Entry<String, String> e : fields.entrySet()) {
406
					if (e.getValue() != null && !e.getValue().isEmpty()) {
407
						final Element field = iface.addElement("INTERFACE_EXTRA_FIELD");
408
						field.addAttribute("name", e.getKey());
409
						field.addText(e.getValue());
410
					}
411
				}
412
				serviceLocator.getService(ISRegistryService.class).updateProfile(repoId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
413
			} else {
414
				log.error("Invalid interface: " + ifaceId);
415
				throw new DatasourceManagerServiceException("Missing interface: " + ifaceId);
416
			}
417
		} catch (Exception e) {
418
			log.error("Error updating API of profile: " + repoId);
419
			throw new DatasourceManagerServiceException("Error updating API of profile: " + repoId, e);
420
		}
421
		return true;
422

    
423
	}
424

    
425
	@Override
426
	public boolean bulkUpdateApiAccessParams(final String dsId, final String ifaceId, final Map<String, String> params)
427
			throws DatasourceManagerServiceException {
428
		return _bulkUpdateApiAccessParams(fixDsId(dsId), ifaceId, params);
429
	}
430

    
431
	private boolean _bulkUpdateApiAccessParams(final String repoId, final String ifaceId, final Map<String, String> params)
432
			throws DatasourceManagerServiceException {
433
		try {
434
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(repoId);
435

    
436
			final SAXReader reader = new SAXReader();
437
			final Document doc = reader.read(new StringReader(profile));
438

    
439
			final Element accessNode = (Element) doc.selectSingleNode("//INTERFACE[@id='" + ifaceId + "']/ACCESS_PROTOCOL");
440
			if (accessNode != null) {
441
				while (accessNode.attributes().size() > 0) {
442
					accessNode.selectSingleNode("@*").detach();
443
				}
444
				for (Map.Entry<String, String> e : params.entrySet()) {
445
					if (e.getValue() != null && !e.getValue().isEmpty()) {
446
						if (e.getKey().equalsIgnoreCase("baseUrl")) {
447
							doc.selectSingleNode("//INTERFACE[@id='" + ifaceId + "']/BASE_URL").setText(e.getValue());
448
						} else {
449
							accessNode.addAttribute(e.getKey(), e.getValue());
450
						}
451
					}
452
				}
453
				serviceLocator.getService(ISRegistryService.class).updateProfile(repoId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
454
			} else {
455
				log.error("Invalid interface: " + ifaceId);
456
				throw new DatasourceManagerServiceException("Missing interface: " + ifaceId);
457
			}
458
		} catch (Exception e) {
459
			log.error("Error updating API of profile: " + repoId);
460
			throw new DatasourceManagerServiceException("Error updating API of profile: " + repoId, e);
461
		}
462
		return true;
463
	}
464

    
465
	@Override
466
	public boolean overrideCompliance(final String dsId, final String ifaceId, final String level) throws DatasourceManagerServiceException {
467
		return _overrideCompliance(fixDsId(dsId), ifaceId, level);
468
	}
469

    
470
	private boolean _overrideCompliance(final String repoId, final String ifaceId, final String compliance) throws DatasourceManagerServiceException {
471
		try {
472
			final String profile = serviceLocator.getService(ISLookUpService.class).getResourceProfile(repoId);
473

    
474
			final SAXReader reader = new SAXReader();
475
			final Document doc = reader.read(new StringReader(profile));
476

    
477
			final Element iface = (Element) doc.selectSingleNode("//INTERFACE[@id='" + ifaceId + "']");
478
			if (iface != null) {
479
				final Map<String, String> fields = Maps.newHashMap();
480

    
481
				if (!StringUtils.isEmpty(compliance)) {
482
					fields.put(DatasourceConstants.OVERRIDING_COMPLIANCE_FIELD, compliance);
483
				}
484

    
485
				while (iface.selectNodes("./INTERFACE_EXTRA_FIELD").size() > 0) {
486
					final Node node = iface.selectSingleNode("./INTERFACE_EXTRA_FIELD");
487
					final String name = node.valueOf("@name");
488

    
489
					if (!name.equals(DatasourceConstants.OVERRIDING_COMPLIANCE_FIELD)) {
490
						fields.put(node.valueOf("@name"), node.getText());
491
					}
492
					node.detach();
493
				}
494

    
495
				for (Map.Entry<String, String> e : fields.entrySet()) {
496
					if (e.getValue() != null && !e.getValue().isEmpty()) {
497
						final Element field = iface.addElement("INTERFACE_EXTRA_FIELD");
498
						field.addAttribute("name", e.getKey());
499
						field.addText(e.getValue());
500
					}
501
				}
502
				serviceLocator.getService(ISRegistryService.class).updateProfile(repoId, doc.asXML(), REPOSITORY_RESOURCE_TYPE);
503
			} else {
504
				log.error("Invalid interface: " + ifaceId);
505
				throw new DatasourceManagerServiceException("Missing interface: " + ifaceId);
506
			}
507
		} catch (Exception e) {
508
			log.error("Error updating API of profile: " + repoId);
509
			throw new DatasourceManagerServiceException("Error updating API of profile: " + repoId, e);
510
		}
511

    
512
		return true;
513
	}
514

    
515
	@Override
516
	public List<BrowsableField> listBrowsableFields() throws DatasourceManagerServiceException {
517
		return Lists.transform(getBrowsableFields(), new Function<XmlBrowsableField, BrowsableField>() {
518

    
519
			@Override
520
			public BrowsableField apply(final XmlBrowsableField f) {
521
				return new BrowsableField(f.getId(), f.getLabel());
522
			}
523
		});
524
	}
525

    
526
	@Override
527
	public List<BrowseTerm> browseField(final String f) throws DatasourceManagerServiceException {
528

    
529
		final List<BrowseTerm> list = Lists.newArrayList();
530

    
531
		try {
532
			final XmlBrowsableField field = findBrowseField(f);
533
			if (field != null) {
534
				final StringTemplate st = new StringTemplate(IOUtils.toString(browseRepoApisQueryTmpl.getInputStream()));
535
				st.setAttribute("xpath", field.getXpath());
536

    
537
				final Map<String, String> terms = fetchVocabularyTerms(field.getVocabulary());
538

    
539
				for (String s : serviceLocator.getService(ISLookUpService.class).quickSearchProfile(st.toString())) {
540
					final String[] arr = s.split("@-@-@");
541
					final String id = arr[0].trim();
542
					final int count = NumberUtils.toInt(arr[1].trim(), 0);
543
					list.add(new BrowseTerm(id, findLabel(id, terms), count));
544
				}
545
			}
546
		} catch (Exception e) {
547
			log.error("Error browsing field " + f, e);
548
		}
549

    
550
		return list;
551
	}
552

    
553
	private String findLabel(final String code, final Map<String, String> terms) {
554
		return terms.containsKey(code) ? terms.get(code) : code;
555
	}
556

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

    
561
		final Map<String, String> map = Maps.newHashMap();
562
		for (String s : serviceLocator.getService(ISLookUpService.class).quickSearchProfile(xquery)) {
563
			final String[] arr = s.split("@@@");
564
			map.put(arr[0].trim(), arr[1].trim());
565
		}
566
		return map;
567
	}
568

    
569
	private XmlBrowsableField findBrowseField(final String id) {
570
		for (XmlBrowsableField f : getBrowsableFields()) {
571
			if (f.getId().equals(id)) { return f; }
572
		}
573
		return null;
574
	}
575

    
576
	@Override
577
	public List<SearchInterfacesEntry> searchInterface(final String field, final String value) throws DatasourceManagerServiceException {
578
		try {
579

    
580
			final StringTemplate st = new StringTemplate();
581
			st.setTemplate(IOUtils.toString(findRepoApisQueryTmpl.getInputStream()));
582

    
583
			if (field.equalsIgnoreCase("__search__")) {
584
				st.setAttribute("cond", "contains(../..//(*|@*)/lower-case(.), '" + StringEscapeUtils.escapeXml(value.toLowerCase()) + "')");
585
			} else {
586
				final XmlBrowsableField f = findBrowseField(field);
587
				if (f != null) {
588
					st.setAttribute("cond", f.getXpath() + "='" + StringEscapeUtils.escapeXml(value) + "'");
589
				} else {
590
					return Lists.newArrayList();
591
				}
592
			}
593

    
594
			final String query = st.toString();
595

    
596
			final SAXReader reader = new SAXReader();
597

    
598
			final List<String> list = serviceLocator.getService(ISLookUpService.class).quickSearchProfile(query);
599

    
600
			return Lists.transform(list, new Function<String, SearchInterfacesEntry>() {
601

    
602
				@Override
603
				public SearchInterfacesEntry apply(final String s) {
604
					final SearchInterfacesEntry iface = new SearchInterfacesEntry();
605
					try {
606
						final Document doc = reader.read(new StringReader(s));
607
						final String country = doc.valueOf("//REPO/@country");
608

    
609
						iface.setRepoId(doc.valueOf("//REPO/@id"));
610
						iface.setRepoCountry(StringUtils.isEmpty(country) ? "-" : country.toUpperCase());
611
						iface.setRepoName(doc.valueOf("//REPO/@name"));
612
						iface.setRepoPrefix(doc.valueOf("//REPO/@prefix"));
613

    
614
						final Node ifcNode = doc.selectSingleNode("//INTERFACE");
615

    
616
						iface.setId(ifcNode.valueOf("./@id"));
617
						iface.setActive(Boolean.valueOf(ifcNode.valueOf("./@active")));
618
						iface.setProtocol(ifcNode.valueOf("./ACCESS_PROTOCOL/text()"));
619

    
620
						final String overCompliance = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='overriding_compliance']");
621
						if (StringUtils.isEmpty(overCompliance)) {
622
							iface.setCompliance(ifcNode.valueOf("@compliance"));
623
						} else {
624
							iface.setCompliance(overCompliance);
625
						}
626

    
627
						final String lastAggregationDate = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_aggregation_date']");
628
						if (!StringUtils.isEmpty(lastAggregationDate)) {
629
							iface.setAggrDate(lastAggregationDate);
630
						} else {
631
							final String lastDownloadDate = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_download_date']");
632
							if (!StringUtils.isEmpty(lastDownloadDate)) {
633
								iface.setAggrDate(lastDownloadDate);
634
							}
635
						}
636
						final String lastAggregationTotal = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_aggregation_total']");
637
						if (StringUtils.isEmpty(lastAggregationTotal)) {
638
							final String lastDownloadTotal = ifcNode.valueOf("./INTERFACE_EXTRA_FIELD[@name='last_download_total']");
639
							if (StringUtils.isEmpty(lastDownloadTotal)) {
640
								iface.setAggrTotal(0);
641
							} else {
642
								iface.setAggrTotal(NumberUtils.toInt(lastDownloadTotal, 0));
643
							}
644
						} else {
645
							iface.setAggrTotal(NumberUtils.toInt(lastAggregationTotal, 0));
646
						}
647
					} catch (Exception e) {
648
						log.error(e);
649
					}
650
					return iface;
651
				}
652
			});
653
		} catch (Exception e) {
654
			log.error("Error searching field " + field + " - value: " + value, e);
655
		}
656
		return Lists.newArrayList();
657
	}
658

    
659
	@Override
660
	public List<RepositoryMapEntry> getRepositoryMap() throws DatasourceManagerServiceException {
661
		try {
662
			final SAXReader reader = new SAXReader();
663

    
664
			final String query = IOUtils.toString(findReposMapQuery.getInputStream());
665
			final List<String> list = serviceLocator.getService(ISLookUpService.class).quickSearchProfile(query);
666
			return Lists.transform(list, new Function<String, RepositoryMapEntry>() {
667

    
668
				@Override
669
				public RepositoryMapEntry apply(final String s) {
670
					final RepositoryMapEntry r = new RepositoryMapEntry();
671

    
672
					try {
673
						final Document doc = reader.read(new StringReader(s));
674
						r.setId(doc.valueOf("//dsId"));
675
						r.setName(doc.valueOf("//name"));
676
						r.setLat(Float.parseFloat(doc.valueOf("//lat")));
677
						r.setLng(Float.parseFloat(doc.valueOf("//lng")));
678
					} catch (Exception e) {
679
						log.error(e);
680
					}
681
					return r;
682
				}
683
			});
684
		} catch (Exception e) {
685
			log.error("Error obtaing repo map entries", e);
686
		}
687
		return Lists.newArrayList();
688
	}
689

    
690
	private List<XmlBrowsableField> getBrowsableFields() {
691
		return browsableFields;
692
	}
693

    
694
	@Required
695
	public void setBrowsableFields(final List<XmlBrowsableField> browsableFields) {
696
		this.browsableFields = browsableFields;
697
	}
698

    
699
	@Override
700
	public List<SimpleDatasourceDesc> simpleListDatasourcesByType(final String type) throws DatasourceManagerServiceException {
701
		try {
702
			final List<SimpleDatasourceDesc> list = Lists.newArrayList();
703

    
704
			final StringTemplate st = new StringTemplate(IOUtils.toString(simpleFindReposQueryTmpl.getInputStream()));
705
			st.setAttribute("type", type);
706

    
707
			for (String s : serviceLocator.getService(ISLookUpService.class).quickSearchProfile(st.toString())) {
708
				final SimpleDatasourceDesc r = new SimpleDatasourceDesc();
709
				final String[] arr = s.split("@=@");
710
				r.setId(arr[0].trim());
711
				r.setName(arr[1].trim());
712
				r.setOrigId(arr[2].trim());
713
				r.setApis(Sets.newHashSet(arr[3].replaceAll("\\s", "").split(",")));
714
				r.setValid("true".equals(arr[4].trim()));
715
				r.setTypology(type);
716
				list.add(r);
717
			}
718

    
719
			Collections.sort(list);
720

    
721
			return list;
722
		} catch (Exception e) {
723
			log.error("Error listing repos", e);
724
		}
725
		return Lists.newArrayList();
726
	}
727

    
728
	public String getEnvironment() {
729
		return environment;
730
	}
731

    
732
	@Required
733
	public void setEnvironment(final String environment) {
734
		this.environment = environment;
735
	}
736

    
737
}
(2-2/5)