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

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

    
42
	private DatasourceManagerClients datasourceManagerClients;
43

    
44
	private List<DbBrowsableField> browsableFields;
45

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

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

    
65
	private static final Log log = LogFactory.getLog(LocalOpenaireDatasourceManager.class);
66

    
67
	private static final String REPO_PROFILEID_SUFFIX = "_UmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZXMvUmVwb3NpdG9yeVNlcnZpY2VSZXNvdXJjZVR5cGU=";
68

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

    
81
	@Override
82
	public List<SimpleDatasource> searchDatasourcesByType(final String type) throws DsmException {
83
		return datasourceManagerClients.searchSQL(searchDsByType, ImmutableMap.of("type", type))
84
				.stream()
85
				.map(DatasourceFunctions::mapToSimpleDs)
86
				.collect(Collectors.toList());
87
	}
88

    
89
	@Override
90
	public List<? extends SearchApisEntry> searchApis(final String field, final Object value) throws DsmException {
91
		try {
92
			final StringWriter sql = new StringWriter();
93

    
94
			if (field.equalsIgnoreCase("__search__")) {
95
				sql.append(IOUtils.toString(searchApis.getInputStream()));
96
			} else {
97
				sql.append(IOUtils.toString(searchApisUsingField.getInputStream()));
98
				sql.append(field);
99
				sql.append("::text = ");
100
				sql.append(":value");
101
			}
102

    
103
			return datasourceManagerClients
104
					.searchSQL(sql.toString(), ImmutableMap.of("value", field.equalsIgnoreCase("__search__") ? "%" + value + "%" : value))
105
					.stream()
106
					.map(DatasourceFunctions::mapToSearchApisEntry)
107
					.collect(Collectors.toList());
108

    
109
		} catch (final Exception e) {
110
			log.error("Error searching field " + field + " - value: " + value, e);
111
		}
112
		return new ArrayList<>();
113
	}
114

    
115
	@Override
116
	public void saveDs(final Datasource<Organization<?>, Identity> ds) throws DsmException {
117

    
118
		if (StringUtils.isBlank(ds.getAggregator())) {
119
			ds.setAggregator("OPENAIRE");
120
		}
121

    
122
		ds.setManaged(true);
123

    
124
		datasourceManagerClients.updateSQL(ds.getId(), addDs, AfterSqlUpdate.NONE, DatasourceFunctions.dsToMap(ds));
125

    
126
		if (ds.getOrganizations() != null) {
127
			for (final Organization<?> org : ds.getOrganizations()) {
128
				final Map<String, Object> orgParams = DatasourceFunctions.orgToMap(ds.getId(), org);
129
				datasourceManagerClients.updateSQL(ds.getId(), addOrg, AfterSqlUpdate.NONE, orgParams);
130
			}
131
		}
132

    
133
		datasourceManagerClients.regenerateProfile(ds.getId());
134
	}
135

    
136
	@Override
137
	public void deleteDs(final String dsId) throws DsmException {
138
		datasourceManagerClients.updateSQL(fixDsId(dsId), deleteDs, AfterSqlUpdate.DELETE_DS_PROFILE, ImmutableMap.of("dsId", dsId));
139
	}
140

    
141
	@Override
142
	public Datasource<Organization<?>, Identity> getDs(final String dsId) throws DsmException {
143
		return datasourceManagerClients.getDatasourceById(fixDsId(dsId));
144
	}
145

    
146
	@Override
147
	public void regenerateProfiles() throws DsmException {
148
		datasourceManagerClients.regenerateProfiles();
149
	}
150

    
151
	@Override
152
	public List<Api<ApiParam>> getApis(final String dsId) throws DsmException {
153
		return datasourceManagerClients.getApis(fixDsId(dsId));
154
	}
155

    
156
	@Override
157
	public void setManaged(final String dsId, final boolean managed) throws DsmException {
158
		final String id = fixDsId(dsId);
159

    
160
		final Map<String, Object> params = new HashMap<>();
161
		params.put("managed", managed);
162
		params.put("dsId", id);
163

    
164
		datasourceManagerClients.updateSQL(id, setManaged, AfterSqlUpdate.UPDATE_DS_PROFILE, params);
165

    
166
	}
167

    
168
	@Override
169
	public boolean isManaged(final String dsId) throws DsmException {
170
		final String q = "SELECT * from dsm_datasources WHERE id = :dsId AND managed = true";
171
		return !datasourceManagerClients.searchSQL(q, ImmutableMap.of("dsId", fixDsId(dsId))).isEmpty();
172
	}
173

    
174
	@Override
175
	public void setActive(final String dsId, final String apiId, final boolean active) throws DsmException {
176
		final String id = fixDsId(dsId);
177

    
178
		final Map<String, Object> params = new HashMap<>();
179
		params.put("active", active);
180
		params.put("apiId", apiId);
181
		params.put("dsId", id);
182

    
183
		datasourceManagerClients.updateSQL(id, setActive, AfterSqlUpdate.NONE, params);
184
		if (!active) {
185
			setLastCollectionInfo(id, apiId, null, null, null);
186
			setLastAggregationInfo(id, apiId, null, null, null);
187
			setLastDownloadInfo(id, apiId, null, null, null);
188
		}
189

    
190
		setManaged(id, true); // It also update the IS profile
191
	}
192

    
193
	@Override
194
	public boolean isActive(final String dsId, final String apiId) throws DsmException {
195
		final String q = "SELECT * from dsm_api WHERE id = :apiId AND datasource = :dsId AND active = true";
196
		return !datasourceManagerClients.searchSQL(q, ImmutableMap.of("dsId", fixDsId(dsId), "apiId", apiId)).isEmpty();
197
	}
198

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

    
205
	@Override
206
	public void updateCompliance(final String dsId, final String apiId, final String level, final boolean override) throws DsmException {
207
		final String id = fixDsId(dsId);
208

    
209
		if (!override) {
210
			datasourceManagerClients.updateSQL(id, setCompliance, AfterSqlUpdate.NONE, ImmutableMap.of("level", level, "apiId", apiId, "dsId", id));
211
		} else if (level != null) {
212
			datasourceManagerClients.updateSQL(id, overrideCompliance, AfterSqlUpdate.NONE, ImmutableMap.of("level", level, "apiId", apiId, "dsId", id));
213
		} else {
214
			datasourceManagerClients.updateSQL(id, resetCompliance, AfterSqlUpdate.NONE, ImmutableMap.of("apiId", apiId, "dsId", id));
215
		}
216

    
217
		setManaged(id, true); // It also update the IS profile
218
	}
219

    
220
	@Override
221
	public void setLastCollectionInfo(final String dsId, final String apiId, final String mdId, final Integer size, final Date date)
222
			throws DsmException {
223
		setLastOperationInfo(setLastCollectionInfo, fixDsId(dsId), apiId, mdId, size, date);
224
	}
225

    
226
	@Override
227
	public void setLastAggregationInfo(final String dsId, final String apiId, final String mdId, final Integer size, final Date date)
228
			throws DsmException {
229
		setLastOperationInfo(setLastAggregationInfo, fixDsId(dsId), apiId, mdId, size, date);
230
	}
231

    
232
	@Override
233
	public void setLastDownloadInfo(final String dsId, final String apiId, final String objId, final Integer size, final Date date)
234
			throws DsmException {
235
		setLastOperationInfo(setLastDownloadInfo, fixDsId(dsId), apiId, objId, size, date);
236
	}
237

    
238
	private void setLastOperationInfo(final Resource sqlResource, final String dsId, final String apiId, final String mdId, final Integer size, final Date date)
239
			throws DsmException {
240
		final Map<String, Object> params = new HashMap<>();
241
		params.put("dsId", dsId);
242
		params.put("apiId", apiId);
243
		params.put("mdId", mdId);
244
		params.put("total", size);
245
		if (date != null) {
246
			params.put("date", new java.sql.Timestamp(date.getTime()));
247
		}
248

    
249
		datasourceManagerClients.updateSQL(dsId, sqlResource, AfterSqlUpdate.NONE, params);
250

    
251
		setManaged(dsId, true); // It also update the IS profile
252
	}
253

    
254
	@Override
255
	public void updateApiDetails(final String dsId,
256
			final String apiId,
257
			final String metadataIdentifierPath,
258
			final String baseUrl,
259
			final Map<String, String> params)
260
			throws DsmException {
261

    
262
		final String id = fixDsId(dsId);
263

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

    
267
		// Insert new params
268
		for (final Map.Entry<String, String> e : params.entrySet()) {
269
			final Map<String, Object> sqlParams = ImmutableMap.of("param", e.getKey(), "value", e.getValue(), "api", apiId);
270
			datasourceManagerClients.updateSQL(id, insertApiParam, AfterSqlUpdate.NONE, sqlParams);
271
		}
272

    
273
		// Update the BaseURL
274
		datasourceManagerClients.updateSQL(id,
275
				"UPDATE dsm_api SET baseurl = :baseurl WHERE id = :api",
276
				AfterSqlUpdate.NONE,
277
				ImmutableMap.of("baseurl", baseUrl, "api", apiId));
278

    
279
		// Update the metadata_identifier_path
280
		datasourceManagerClients.updateSQL(id,
281
				"UPDATE dsm_api SET metadata_identifier_path = :path WHERE id = :api",
282
				AfterSqlUpdate.NONE,
283
				ImmutableMap.of("path", metadataIdentifierPath, "api", apiId));
284

    
285
		setManaged(id, true); // It also update the IS profile
286
	}
287

    
288
	@Override
289
	public List<? extends BrowsableField> listBrowsableFields() throws DsmException {
290
		return getBrowsableFields();
291
	}
292

    
293
	@Override
294
	public List<BrowseTerm> browseField(final String field) throws DsmException {
295
		final Optional<DbBrowsableField> bf = getBrowsableFields()
296
				.stream()
297
				.filter(f -> f.getId().equals(field))
298
				.findFirst();
299

    
300
		if (bf.isPresent()) {
301
			return datasourceManagerClients.searchSQL(bf.get().getSql(), new HashMap<>())
302
					.stream()
303
					.filter(m -> m.get("term") != null)
304
					.filter(m -> m.get("count") != null)
305
					.filter(m -> StringUtils.isNotBlank(m.get("term").toString()))
306
					.map(m -> new BrowseTermImpl(m.get("term").toString(), NumberUtils.toInt(m.get("count").toString(), 0)))
307
					.collect(Collectors.toList());
308
		} else {
309
			log.error("Not browsable field:" + field);
310
			throw new DsmException("Not browsable field:" + field);
311
		}
312
	}
313

    
314
	@Override
315
	public void addApi(final Api<ApiParam> api) throws DsmException {
316

    
317
		datasourceManagerClients.updateSQL(api.getDatasource(), insertApi, AfterSqlUpdate.NONE, DatasourceFunctions.apiToMap(api));
318

    
319
		api.getApiParams().forEach(p -> {
320
			final ImmutableMap<String, Object> sqlParams = ImmutableMap.of("param", p.getParam(), "value", p.getValue(), "api", api.getId());
321
			try {
322
				datasourceManagerClients.updateSQL(api.getDatasource(), insertApiParam, AfterSqlUpdate.NONE, sqlParams);
323
			} catch (final DsmException e) {
324
				throw new RuntimeException(e);
325
			}
326
		});
327

    
328
		setManaged(api.getDatasource(), true); // It also update the IS profile
329
	}
330

    
331
	@Override
332
	public void deleteApi(final String dsId, final String apiId) throws DsmException {
333
		if (!isRemovable(dsId, apiId)) { throw new DsmException("The api " + apiId + " can't be deleted"); }
334

    
335
		datasourceManagerClients.updateSQL(dsId, "DELETE FROM dsm_apiparams WHERE api = :api", AfterSqlUpdate.NONE, ImmutableMap.of("api", apiId));
336
		datasourceManagerClients.updateSQL(dsId, "DELETE FROM dsm_api WHERE id = :api", AfterSqlUpdate.NONE, ImmutableMap.of("api", apiId));
337

    
338
		setManaged(dsId, true); // It also update the IS profile
339
	}
340

    
341
	public DatasourceManagerClients getDatasourceManagerClients() {
342
		return datasourceManagerClients;
343
	}
344

    
345
	private String fixDsId(final String dsId) throws DsmException {
346
		return dsId.endsWith(REPO_PROFILEID_SUFFIX) ? datasourceManagerClients.findDatasourceId(dsId) : dsId;
347
	}
348

    
349
	@Required
350
	public void setDatasourceManagerClients(final DatasourceManagerClients datasourceManagerClients) {
351
		this.datasourceManagerClients = datasourceManagerClients;
352
	}
353

    
354
	public List<DbBrowsableField> getBrowsableFields() {
355
		return browsableFields;
356
	}
357

    
358
	@Required
359
	public void setBrowsableFields(final List<DbBrowsableField> browsableFields) {
360
		this.browsableFields = browsableFields;
361
	}
362

    
363
}
(4-4/4)