Project

General

Profile

1
package eu.dnetlib.enabling.datasources;
2

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

    
10
import javax.xml.ws.wsaddressing.W3CEndpointReference;
11

    
12
import org.antlr.stringtemplate.StringTemplate;
13
import org.apache.commons.io.IOUtils;
14
import org.apache.commons.logging.Log;
15
import org.apache.commons.logging.LogFactory;
16
import org.dom4j.Document;
17
import org.dom4j.io.SAXReader;
18
import org.quartz.CronExpression;
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.Lists;
24
import com.google.common.collect.Maps;
25

    
26
import eu.dnetlib.enabling.database.rmi.DatabaseException;
27
import eu.dnetlib.enabling.database.rmi.DatabaseService;
28
import eu.dnetlib.enabling.datasources.rmi.DatasourceDesc;
29
import eu.dnetlib.enabling.datasources.rmi.DatasourceManagerServiceException;
30
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException;
31
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
32
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
33
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
34
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
35
import eu.dnetlib.enabling.resultset.client.ResultSetClientFactory;
36
import eu.dnetlib.miscutils.functional.UnaryFunction;
37
import eu.dnetlib.miscutils.functional.xml.ApplyXslt;
38

    
39
public class DatasourceManagerClients {
40

    
41
	private static final Resource xslt = new ClassPathResource("/eu/dnetlib/enabling/datasources/repo_2_is.xslt");
42
	private static final String REPOSITORY_SERVICE_RESOURCE_TYPE = "RepositoryServiceResourceType";
43
	private static final Log log = LogFactory.getLog(DatasourceManagerClients.class);
44
	private static final String TMPLS_BASEDIR = "/eu/dnetlib/enabling/datasources/";
45
	private String db;
46
	private UniqueServiceLocator serviceLocator;
47
	private ResultSetClientFactory resultSetClientFactory;
48

    
49
	public boolean isManaged(final String dsId) throws DatasourceManagerServiceException {
50
		try {
51

    
52

    
53
			serviceLocator.getService(DatabaseService.class).contains(getDb(), "datasources", "managed", "true");
54

    
55

    
56
			return true;
57
		} catch (final DatabaseException e) {
58
			throw new DatasourceManagerServiceException(e);
59
		}
60
	}
61

    
62
	public String findDatasourceId(final String profileId) throws DatasourceManagerServiceException {
63
		try {
64
			return serviceLocator.getService(ISLookUpService.class).getResourceProfileByQuery(
65
					"/*[.//RESOURCE_IDENTIFIER/@value='" + profileId + "']//EXTRA_FIELDS/FIELD[./key='OpenAireDataSourceId']/value/text()");
66
		} catch (final Exception e) {
67
			log.error("Error finding dsId of profile " + profileId, e);
68
			throw new DatasourceManagerServiceException("Error finding dsId of profile " + profileId, e);
69
		}
70
	}
71

    
72
	public String getDatasourceProfile(final String dsId) throws DatasourceManagerServiceException {
73
		try {
74
			return serviceLocator.getService(ISLookUpService.class)
75
					.getResourceProfileByQuery(
76
							"collection('/db/DRIVER/RepositoryServiceResources/RepositoryServiceResourceType')/*[.//EXTRA_FIELDS/FIELD[./key='OpenAireDataSourceId']/value/text() = '"
77
									+ dsId + "']");
78
		} catch (final Exception e) {
79
			return null;
80
		}
81
	}
82

    
83
	public boolean deleteProfile(final String dsId) throws DatasourceManagerServiceException {
84
		try {
85
			final SAXReader reader = new SAXReader();
86

    
87
			final String profile = getDatasourceProfile(dsId);
88

    
89
			if (profile != null) {
90
				final Document docOld = reader.read(new StringReader(profile));
91
				final String profId = docOld.valueOf("//RESOURCE_IDENTIFIER/@value");
92
				serviceLocator.getService(ISRegistryService.class).deleteProfile(profId);
93
			}
94
			return true;
95
		} catch (final Exception e) {
96
			log.error("Error deleting profile", e);
97
			throw new DatasourceManagerServiceException("Error deleting profile", e);
98
		}
99
	}
100

    
101
	public boolean regenerateProfile(final String dsId) throws DatasourceManagerServiceException {
102

    
103
		try {
104
			final SAXReader reader = new SAXReader();
105

    
106
			final List<String> list = getTransformedDatasourcesByCondition("ds.id= '" + dsId + "'", new ApplyXslt(xslt));
107

    
108
			if (list.size() != 1) { throw new DatasourceManagerServiceException("Illegal number of datasource with id " + dsId + ", size: " + list.size()); }
109

    
110
			final Document doc = reader.read(new StringReader(list.get(0)));
111

    
112
			final ISRegistryService registry = serviceLocator.getService(ISRegistryService.class);
113

    
114
			final String profile = getDatasourceProfile(dsId);
115

    
116
			if (profile != null) {
117
				final Document docOld = reader.read(new StringReader(profile));
118
				final String profId = docOld.valueOf("//RESOURCE_IDENTIFIER/@value");
119

    
120
				doc.selectSingleNode("//RESOURCE_IDENTIFIER/@value").setText(profId);
121

    
122
				registry.updateProfile(profId, doc.asXML(), REPOSITORY_SERVICE_RESOURCE_TYPE);
123
				log.info("Profile " + profId + " UPDATED for ds " + dsId);
124
			} else {
125
				final String profId = registry.registerProfile(doc.asXML());
126
				log.info("Valid Profile " + profId + " REGISTERED for ds " + dsId);
127
			}
128
			return true;
129
		} catch (final Exception e) {
130
			log.error("Error saving profile, id: " + dsId, e);
131
			throw new DatasourceManagerServiceException("Error regenerating profile", e);
132
		}
133
	}
134

    
135
	public Iterable<String> searchSQL(final String sql) throws DatabaseException {
136
		final W3CEndpointReference epr = serviceLocator.getService(DatabaseService.class).searchSQL(getDb(), sql);
137
		return resultSetClientFactory.getClient(epr);
138
	}
139

    
140
	public boolean updateSQL(final String dsId, final String sql, final boolean delete, final boolean updateprofile) throws DatasourceManagerServiceException {
141
		log.debug("Executing query SQL: " + sql);
142

    
143
		try {
144
			serviceLocator.getService(DatabaseService.class).updateSQL(getDb(), sql);
145
		} catch (final DatabaseException e) {
146
			throw new DatasourceManagerServiceException(e);
147
		}
148

    
149
		if (updateprofile) {
150
			if (delete) {
151
				return deleteProfile(dsId);
152
			} else {
153
				return regenerateProfile(dsId);
154
			}
155
		}
156
		return false;
157
	}
158

    
159
	public boolean updateSQL(final String dsId, final String sqlTemplate, final Map<String, Object> params, final boolean delete, final boolean updateProfile)
160
			throws DatasourceManagerServiceException {
161

    
162
		verifyParams(params.values());
163
		verifyParams(params.keySet().toArray());
164

    
165
		try {
166
			final Resource resource = new ClassPathResource(TMPLS_BASEDIR + sqlTemplate);
167
			final StringTemplate st = new StringTemplate(IOUtils.toString(resource.getInputStream()));
168
			st.setAttributes(params);
169
			return updateSQL(dsId, st.toString(), delete, updateProfile);
170
		} catch (final Exception e) {
171
			log.error("Error in updateSQL", e);
172
			throw new DatasourceManagerServiceException("Error in updateSQL", e);
173
		}
174
	}
175

    
176
	public List<DatasourceDesc> getDatasourcesByCondition(final String condition) throws DatasourceManagerServiceException {
177
		final SAXReader reader = new SAXReader();
178
		final List<DatasourceDesc> list = Lists.newArrayList();
179
		try {
180
			for (final String s : getXmlDatasourcesByCondition(condition)) {
181
				final Document doc = reader.read(new StringReader(s));
182
				list.add(DatasourceFunctions.xmlToDatasourceDesc(doc));
183
			}
184
		} catch (final Exception e) {
185
			log.error("Error obtaining datasources from db", e);
186
			throw new DatasourceManagerServiceException("Error obtaining datasources from db", e);
187
		}
188
		return list;
189

    
190
	}
191

    
192
	private void verifyParams(final Object... params) throws DatasourceManagerServiceException {
193

    
194
		final Pattern pattern = Pattern.compile("\\n");
195

    
196
		for (final Object p : params) {
197
			log.debug("TESTING SQL PARAM:" + p);
198
			if ((p == null) || p.toString().isEmpty()) {
199
				log.error("Parameter null or empty");
200
				throw new DatasourceManagerServiceException("Parameter null or empty");
201
			} else if (pattern.matcher(p.toString()).matches()) {
202
				log.error("Parameter [" + p + "] contains an invalid character");
203
				throw new DatasourceManagerServiceException("Parameter [" + p + "] contains an invalid character");
204
			} else {
205
				log.debug("TEST OK");
206
			}
207
		}
208
	}
209

    
210
	private List<String> getTransformedDatasourcesByCondition(final String condition, final UnaryFunction<String, String> function)
211
			throws DatasourceManagerServiceException {
212
		final List<String> list = Lists.newArrayList();
213
		try {
214
			for (final String s : getXmlDatasourcesByCondition(condition)) {
215
				list.add(function.evaluate(s));
216
			}
217
		} catch (final Exception e) {
218
			log.error("Error obtaining datasources from db", e);
219
			throw new DatasourceManagerServiceException("Error obtaining datasources from db", e);
220
		}
221
		return list;
222
	}
223

    
224
	private Iterable<String> getXmlDatasourcesByCondition(final String condition) throws DatasourceManagerServiceException {
225
		try {
226
			final Map<String, Object> params = Maps.newHashMap();
227

    
228
			if ((condition != null) && !condition.trim().isEmpty()) {
229
				params.put("condition", condition);
230
			}
231
			return searchSQL("getDatasources.sql.st", params);
232
		} catch (final Exception e) {
233
			log.error("Error obtaining datasources from db", e);
234
			throw new DatasourceManagerServiceException("Error obtaining datasources from db", e);
235
		}
236
	}
237

    
238
	public Iterable<String> searchSQL(final String sqlTemplate, final Map<String, Object> params) throws DatasourceManagerServiceException {
239
		try {
240
			final Resource resource = new ClassPathResource(TMPLS_BASEDIR + sqlTemplate);
241
			final StringTemplate st = new StringTemplate(IOUtils.toString(resource.getInputStream()));
242
			if (params != null) {
243
				st.setAttributes(params);
244
			}
245

    
246
			final String sql = st.toString();
247

    
248
			log.debug("Executing SQL: " + sql);
249

    
250
			return searchSQL(sql);
251
		} catch (final Exception e) {
252
			log.error("Error executing sql", e);
253

    
254
			throw new DatasourceManagerServiceException("Error obtaining datasources from db", e);
255
		}
256
	}
257

    
258
	public boolean isDefinedParam(final String ifaceId, final String field) throws DatasourceManagerServiceException {
259
		final Map<String, Object> params = Maps.newHashMap();
260
		params.put("ifaceId", DatasourceFunctions.asSqlValue(ifaceId));
261
		params.put("field", DatasourceFunctions.asSqlValue(field));
262

    
263
		final List<String> list = Lists.newArrayList(searchSQL("searchApiCollectionParam.sql.st", params));
264

    
265
		return !list.isEmpty();
266
	}
267

    
268
	public Date findNextScheduledExecution(final String dsId, final String ifaceId) throws DatasourceManagerServiceException {
269
		final String xquery = "/*[.//DATAPROVIDER/@interface='" + ifaceId + "' and .//SCHEDULING/@enabled='true']//CRON/text()";
270
		try {
271
			final String cronExpression = serviceLocator.getService(ISLookUpService.class).getResourceProfileByQuery(xquery);
272
			final CronExpression cron = new CronExpression(cronExpression);
273
			return cron.getNextValidTimeAfter(new Date());
274
		} catch (final ISLookUpDocumentNotFoundException e) {
275
			// When the value is not found a null value must be returned
276
			return null;
277
		} catch (final ISLookUpException e) {
278
			log.error("Error in xquery: " + xquery, e);
279
			throw new DatasourceManagerServiceException("Error in xquery: " + xquery, e);
280
		} catch (final ParseException e) {
281
			log.error("Error parsing cron expression", e);
282
			throw new DatasourceManagerServiceException("Error parsing cron expression", e);
283
		}
284
	}
285

    
286
	public String getDb() {
287
		return db;
288
	}
289

    
290
	@Required
291
	public void setDb(final String db) {
292
		this.db = db;
293
	}
294

    
295
	public ResultSetClientFactory getResultSetClientFactory() {
296
		return resultSetClientFactory;
297
	}
298

    
299
	@Required
300
	public void setResultSetClientFactory(final ResultSetClientFactory resultSetClientFactory) {
301
		this.resultSetClientFactory = resultSetClientFactory;
302
	}
303

    
304
	public UniqueServiceLocator getServiceLocator() {
305
		return serviceLocator;
306
	}
307

    
308
	@Required
309
	public void setServiceLocator(final UniqueServiceLocator serviceLocator) {
310
		this.serviceLocator = serviceLocator;
311
	}
312

    
313
}
(2-2/5)