Project

General

Profile

1
package eu.dnetlib.enabling.datasources;
2

    
3
import java.io.StringWriter;
4
import java.util.ArrayList;
5
import java.util.Date;
6
import java.util.HashMap;
7
import java.util.HashSet;
8
import java.util.List;
9
import java.util.Map;
10
import java.util.Optional;
11
import java.util.Set;
12
import java.util.stream.Collectors;
13

    
14
import org.apache.commons.io.IOUtils;
15
import org.apache.commons.lang.StringUtils;
16
import org.apache.commons.lang.math.NumberUtils;
17
import org.apache.commons.logging.Log;
18
import org.apache.commons.logging.LogFactory;
19
import org.springframework.beans.factory.annotation.Required;
20
import org.springframework.core.io.ClassPathResource;
21
import org.springframework.core.io.Resource;
22

    
23
import com.google.common.collect.ImmutableMap;
24

    
25
import eu.dnetlib.enabling.datasources.DatasourceManagerClients.AfterSqlUpdate;
26
import eu.dnetlib.enabling.datasources.common.Api;
27
import eu.dnetlib.enabling.datasources.common.ApiParam;
28
import eu.dnetlib.enabling.datasources.common.BrowsableField;
29
import eu.dnetlib.enabling.datasources.common.BrowseTerm;
30
import eu.dnetlib.enabling.datasources.common.BrowseTermImpl;
31
import eu.dnetlib.enabling.datasources.common.Datasource;
32
import eu.dnetlib.enabling.datasources.common.DsmException;
33
import eu.dnetlib.enabling.datasources.common.DsmRuntimeException;
34
import eu.dnetlib.enabling.datasources.common.Identity;
35
import eu.dnetlib.enabling.datasources.common.LocalDatasourceManager;
36
import eu.dnetlib.enabling.datasources.common.Organization;
37
import eu.dnetlib.enabling.datasources.common.SearchApisEntry;
38
import eu.dnetlib.enabling.datasources.common.SimpleDatasource;
39
import org.springframework.transaction.annotation.Transactional;
40

    
41
public class LocalOpenaireDatasourceManager implements LocalDatasourceManager<Datasource<Organization<?>, Identity>, Api<ApiParam>> {
42

    
43
	private DatasourceManagerClients datasourceManagerClients;
44

    
45
	private List<DbBrowsableField> browsableFields;
46

    
47
	public static final String QUERY_BASEDIR = "/eu/dnetlib/enabling/datasources/queries/";
48

    
49
	private static final Resource searchDsByType = new ClassPathResource(QUERY_BASEDIR + "searchDsByType.sql");
50
	private static final Resource searchApis = new ClassPathResource(QUERY_BASEDIR + "searchApisNormal.sql");
51
	private static final Resource searchApisUsingField = new ClassPathResource(QUERY_BASEDIR + "searchApisUsingField.sql");
52
	private static final Resource addDs = new ClassPathResource(QUERY_BASEDIR + "addDatasource.sql");
53
	private static final Resource addOrg = new ClassPathResource(QUERY_BASEDIR + "addOrganization.sql");
54
	private static final Resource deleteDs = new ClassPathResource(QUERY_BASEDIR + "deleteDatasource.sql");
55
	private static final Resource setActive = new ClassPathResource(QUERY_BASEDIR + "setActive.sql");
56
	private static final Resource setManaged = new ClassPathResource(QUERY_BASEDIR + "setManaged.sql");
57
	private static final Resource setCompliance = new ClassPathResource(QUERY_BASEDIR + "setCompliance.sql");
58
	private static final Resource overrideCompliance = new ClassPathResource(QUERY_BASEDIR + "overrideCompliance.sql");
59
	private static final Resource resetCompliance = new ClassPathResource(QUERY_BASEDIR + "resetCompliance.sql");
60
	private static final Resource setLastCollectionInfo = new ClassPathResource(QUERY_BASEDIR + "setLastCollectionInfo.sql");
61
	private static final Resource setLastAggregationInfo = new ClassPathResource(QUERY_BASEDIR + "setLastAggregationInfo.sql");
62
	private static final Resource setLastDownloadInfo = new ClassPathResource(QUERY_BASEDIR + "setLastDownloadInfo.sql");
63
	private static final Resource resetLastOperationsInfo = new ClassPathResource(QUERY_BASEDIR + "resetLastOperationsInfo.sql");
64
	private static final Resource insertApiParam = new ClassPathResource(QUERY_BASEDIR + "insertApiParam.sql");
65
	private static final Resource insertApi = new ClassPathResource(QUERY_BASEDIR + "insertApi.sql");
66

    
67
	private static final Log log = LogFactory.getLog(LocalOpenaireDatasourceManager.class);
68

    
69
	private static final String REPO_PROFILEID_SUFFIX = "_UmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZXMvUmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZVR5cGU=";
70

    
71
	@Override
72
	@Transactional(readOnly = true)
73
	public Set<String> listManagedDatasourceIds() throws DsmRuntimeException {
74
		try {
75
			return datasourceManagerClients.searchSQL("SELECT id FROM dsm_datasources WHERE managed = true", new HashMap<>())
76
					.stream()
77
					.map(m -> (String) m.get("id"))
78
					.collect(Collectors.toCollection(HashSet::new));
79
		} catch (final DsmException e) {
80
			throw new DsmRuntimeException(e);
81
		}
82
	}
83

    
84
	@Override
85
	@Transactional(readOnly = true)
86
	public List<SimpleDatasource> searchDatasourcesByType(final String type) throws DsmException {
87

    
88
		return datasourceManagerClients.searchSQL(searchDsByType, ImmutableMap.of("type", type))
89
				.stream()
90
				.map(DatasourceFunctions::mapToSimpleDs)
91
				.collect(Collectors.toList());
92
	}
93

    
94
	@Override
95
	@Transactional(readOnly = true)
96
	public List<? extends SearchApisEntry> searchApis(final String field, final Object value) throws DsmException {
97
		try {
98
			final StringWriter sql = new StringWriter();
99

    
100
			if (field.equalsIgnoreCase("__search__")) {
101
				sql.append(IOUtils.toString(searchApis.getInputStream()));
102
			} else {
103
				sql.append(IOUtils.toString(searchApisUsingField.getInputStream()));
104
				sql.append(field);
105
				sql.append("::text = ");
106
				sql.append(":value");
107
			}
108

    
109
			return datasourceManagerClients
110
					.searchSQL(sql.toString(), ImmutableMap.of("value", field.equalsIgnoreCase("__search__") ? "%" + value + "%" : value))
111
					.stream()
112
					.map(DatasourceFunctions::mapToSearchApisEntry)
113
					.collect(Collectors.toList());
114

    
115
		} catch (final Exception e) {
116
			log.error("Error searching field " + field + " - value: " + value, e);
117
		}
118
		return new ArrayList<>();
119
	}
120

    
121
	@Override
122
	@Transactional
123
	public void saveDs(final Datasource<Organization<?>, Identity> ds) throws DsmException {
124

    
125
		if (StringUtils.isBlank(ds.getAggregator())) {
126
			ds.setAggregator("OPENAIRE");
127
		}
128

    
129
		ds.setManaged(true);
130

    
131
		datasourceManagerClients.updateSQL(ds.getId(), addDs, AfterSqlUpdate.NONE, DatasourceFunctions.dsToMap(ds));
132

    
133
		if (ds.getOrganizations() != null) {
134
			for (final Organization<?> org : ds.getOrganizations()) {
135
				final Map<String, Object> orgParams = DatasourceFunctions.orgToMap(ds.getId(), org);
136
				datasourceManagerClients.updateSQL(ds.getId(), addOrg, AfterSqlUpdate.NONE, orgParams);
137
			}
138
		}
139

    
140
		datasourceManagerClients.regenerateProfile(ds.getId());
141
	}
142

    
143
	@Override
144
	@Transactional
145
	public void deleteDs(final String dsId) throws DsmException {
146
		datasourceManagerClients.updateSQL(fixDsId(dsId), deleteDs, AfterSqlUpdate.DELETE_DS_PROFILE, ImmutableMap.of("dsId", dsId));
147
	}
148

    
149
	@Override
150
	public Datasource<Organization<?>, Identity> getDs(final String dsId) throws DsmException {
151
		return datasourceManagerClients.getDatasourceById(fixDsId(dsId));
152
	}
153

    
154
	@Override
155
	public void regenerateProfiles() throws DsmException {
156
		datasourceManagerClients.regenerateProfiles();
157
	}
158

    
159
	@Override
160
	public List<Api<ApiParam>> getApis(final String dsId) throws DsmException {
161
		return datasourceManagerClients.getApis(fixDsId(dsId));
162
	}
163

    
164
	@Override
165
	public void setManaged(final String dsId, final boolean managed) throws DsmException {
166
		final String id = fixDsId(dsId);
167

    
168
		final Map<String, Object> params = new HashMap<>();
169
		params.put("managed", managed);
170
		params.put("dsId", id);
171

    
172
		datasourceManagerClients.updateSQL(id, setManaged, AfterSqlUpdate.UPDATE_DS_PROFILE, params);
173

    
174
	}
175

    
176
	@Override
177
	public boolean isManaged(final String dsId) throws DsmException {
178
		final String q = "SELECT * from dsm_datasources WHERE id = :dsId AND managed = true";
179
		return !datasourceManagerClients.searchSQL(q, ImmutableMap.of("dsId", fixDsId(dsId))).isEmpty();
180
	}
181

    
182
	@Override
183
	@Transactional
184
	public void setActive(final String dsId, final String apiId, final boolean active) throws DsmException {
185
		final String id = fixDsId(dsId);
186

    
187
		final Map<String, Object> params = new HashMap<>();
188
		params.put("active", active);
189
		params.put("apiId", apiId);
190
		params.put("dsId", id);
191

    
192
		datasourceManagerClients.updateSQL(id, setActive, AfterSqlUpdate.NONE, params);
193
		if (!active) {
194
			datasourceManagerClients.updateSQL(dsId, resetLastOperationsInfo, AfterSqlUpdate.NONE, params);
195
		}
196

    
197
		setManaged(id, true); // It also update the IS profile
198
	}
199

    
200
	@Override
201
	@Transactional(readOnly = true)
202
	public boolean isActive(final String dsId, final String apiId) throws DsmException {
203
		final String q = "SELECT * from dsm_api WHERE id = :apiId AND datasource = :dsId AND active = true";
204
		return !datasourceManagerClients.searchSQL(q, ImmutableMap.of("dsId", fixDsId(dsId), "apiId", apiId)).isEmpty();
205
	}
206

    
207
	@Override
208
	@Transactional(readOnly = true)
209
	public boolean isRemovable(final String dsId, final String apiId) throws DsmException {
210
		final String q = "SELECT * from dsm_api WHERE id = :apiId AND datasource = :dsId AND active != true AND removable = true";
211
		return !datasourceManagerClients.searchSQL(q, ImmutableMap.of("dsId", fixDsId(dsId), "apiId", apiId)).isEmpty();
212
	}
213

    
214
	@Override
215
	@Transactional
216
	public void updateCompliance(final String dsId, final String apiId, final String level, final boolean override) throws DsmException {
217
		final String id = fixDsId(dsId);
218

    
219
		if (!override) {
220
			datasourceManagerClients.updateSQL(id, setCompliance, AfterSqlUpdate.NONE, ImmutableMap.of("level", level, "apiId", apiId, "dsId", id));
221
		} else if (level != null) {
222
			datasourceManagerClients.updateSQL(id, overrideCompliance, AfterSqlUpdate.NONE, ImmutableMap.of("level", level, "apiId", apiId, "dsId", id));
223
		} else {
224
			datasourceManagerClients.updateSQL(id, resetCompliance, AfterSqlUpdate.NONE, ImmutableMap.of("apiId", apiId, "dsId", id));
225
		}
226

    
227
		setManaged(id, true); // It also update the IS profile
228
	}
229

    
230
	@Override
231

    
232
	public void setLastCollectionInfo(final String dsId, final String apiId, final String mdId, final Integer size, final Date date)
233
			throws DsmException {
234
		setLastOperationInfo(setLastCollectionInfo, fixDsId(dsId), apiId, mdId, size, date);
235
	}
236

    
237
	@Override
238
	public void setLastAggregationInfo(final String dsId, final String apiId, final String mdId, final Integer size, final Date date)
239
			throws DsmException {
240
		setLastOperationInfo(setLastAggregationInfo, fixDsId(dsId), apiId, mdId, size, date);
241
	}
242

    
243
	@Override
244
	public void setLastDownloadInfo(final String dsId, final String apiId, final String objId, final Integer size, final Date date)
245
			throws DsmException {
246
		setLastOperationInfo(setLastDownloadInfo, fixDsId(dsId), apiId, objId, size, date);
247
	}
248

    
249
	@Transactional
250
	protected void setLastOperationInfo(final Resource sqlResource, final String dsId, final String apiId, final String mdId, final Integer size, final Date date)
251
			throws DsmException {
252
		final Map<String, Object> params = new HashMap<>();
253
		params.put("dsId", dsId);
254
		params.put("apiId", apiId);
255
		params.put("mdId", mdId);
256
		params.put("total", size);
257
		if (date != null) {
258
			params.put("date", new java.sql.Timestamp(date.getTime()));
259
		}
260

    
261
		datasourceManagerClients.updateSQL(dsId, sqlResource, AfterSqlUpdate.NONE, params);
262

    
263
		setManaged(dsId, true); // It also update the IS profile
264
	}
265

    
266
	@Override
267
	@Transactional
268
	public void updateApiDetails(final String dsId,
269
			final String apiId,
270
			final String metadataIdentifierPath,
271
			final String baseUrl,
272
			final Map<String, String> params)
273
			throws DsmException {
274

    
275
		final String id = fixDsId(dsId);
276

    
277
		// Delete old params
278
		datasourceManagerClients.updateSQL(id, "DELETE FROM dsm_apiparams WHERE api = :api", AfterSqlUpdate.NONE, ImmutableMap.of("api", apiId));
279

    
280
		// Insert new params
281
		for (final Map.Entry<String, String> e : params.entrySet()) {
282
			final Map<String, Object> sqlParams = ImmutableMap.of("param", e.getKey(), "value", e.getValue(), "api", apiId);
283
			datasourceManagerClients.updateSQL(id, insertApiParam, AfterSqlUpdate.NONE, sqlParams);
284
		}
285

    
286
		// Update the BaseURL
287
		datasourceManagerClients.updateSQL(id,
288
				"UPDATE dsm_api SET baseurl = :baseurl WHERE id = :api",
289
				AfterSqlUpdate.NONE,
290
				ImmutableMap.of("baseurl", baseUrl, "api", apiId));
291

    
292
		// Update the metadata_identifier_path
293
		datasourceManagerClients.updateSQL(id,
294
				"UPDATE dsm_api SET metadata_identifier_path = :path WHERE id = :api",
295
				AfterSqlUpdate.NONE,
296
				ImmutableMap.of("path", metadataIdentifierPath, "api", apiId));
297

    
298
		setManaged(id, true); // It also update the IS profile
299
	}
300

    
301
	@Override
302
	public List<? extends BrowsableField> listBrowsableFields() throws DsmException {
303
		return getBrowsableFields();
304
	}
305

    
306
	@Override
307
	public List<BrowseTerm> browseField(final String field) throws DsmException {
308
		final Optional<DbBrowsableField> bf = getBrowsableFields()
309
				.stream()
310
				.filter(f -> f.getId().equals(field))
311
				.findFirst();
312

    
313
		if (bf.isPresent()) {
314
			return datasourceManagerClients.searchSQL(bf.get().getSql(), new HashMap<>())
315
					.stream()
316
					.filter(m -> m.get("term") != null)
317
					.filter(m -> m.get("count") != null)
318
					.filter(m -> StringUtils.isNotBlank(m.get("term").toString()))
319
					.map(m -> new BrowseTermImpl(m.get("term").toString(), NumberUtils.toInt(m.get("count").toString(), 0)))
320
					.collect(Collectors.toList());
321
		} else {
322
			log.error("Not browsable field:" + field);
323
			throw new DsmException("Not browsable field:" + field);
324
		}
325
	}
326

    
327
	@Override
328
	@Transactional
329
	public void addApi(final Api<ApiParam> api) throws DsmException {
330

    
331
		datasourceManagerClients.updateSQL(api.getDatasource(), insertApi, AfterSqlUpdate.NONE, DatasourceFunctions.apiToMap(api));
332

    
333
		api.getApiParams().forEach(p -> {
334
			final ImmutableMap<String, Object> sqlParams = ImmutableMap.of("param", p.getParam(), "value", p.getValue(), "api", api.getId());
335
			try {
336
				datasourceManagerClients.updateSQL(api.getDatasource(), insertApiParam, AfterSqlUpdate.NONE, sqlParams);
337
			} catch (final DsmException e) {
338
				throw new RuntimeException(e);
339
			}
340
		});
341

    
342
		setManaged(api.getDatasource(), true); // It also update the IS profile
343
	}
344

    
345
	@Override
346
	@Transactional
347
	public void deleteApi(final String dsId, final String apiId) throws DsmException {
348
		if (!isRemovable(dsId, apiId)) { throw new DsmException("The api " + apiId + " can't be deleted"); }
349

    
350
		datasourceManagerClients.updateSQL(dsId, "DELETE FROM dsm_apiparams WHERE api = :api", AfterSqlUpdate.NONE, ImmutableMap.of("api", apiId));
351
		datasourceManagerClients.updateSQL(dsId, "DELETE FROM dsm_api WHERE id = :api", AfterSqlUpdate.NONE, ImmutableMap.of("api", apiId));
352

    
353
		setManaged(dsId, true); // It also update the IS profile
354
	}
355

    
356
	public DatasourceManagerClients getDatasourceManagerClients() {
357
		return datasourceManagerClients;
358
	}
359

    
360
	private String fixDsId(final String dsId) throws DsmException {
361
		return dsId.endsWith(REPO_PROFILEID_SUFFIX) ? datasourceManagerClients.findDatasourceId(dsId) : dsId;
362
	}
363

    
364
	@Required
365
	public void setDatasourceManagerClients(final DatasourceManagerClients datasourceManagerClients) {
366
		this.datasourceManagerClients = datasourceManagerClients;
367
	}
368

    
369
	public List<DbBrowsableField> getBrowsableFields() {
370
		return browsableFields;
371
	}
372

    
373
	@Required
374
	public void setBrowsableFields(final List<DbBrowsableField> browsableFields) {
375
		this.browsableFields = browsableFields;
376
	}
377

    
378
}
(4-4/4)