Project

General

Profile

1
package eu.dnetlib.openaire.directindex.objects;
2

    
3
import java.text.SimpleDateFormat;
4
import java.util.ArrayList;
5
import java.util.Date;
6
import java.util.HashMap;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.concurrent.TimeUnit;
10

    
11
import org.apache.commons.lang.StringUtils;
12
import org.apache.commons.logging.Log;
13
import org.apache.commons.logging.LogFactory;
14
import org.apache.velocity.app.VelocityEngine;
15
import org.springframework.ui.velocity.VelocityEngineUtils;
16

    
17
import com.google.gson.Gson;
18

    
19
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
20
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
21
import eu.dnetlib.miscutils.datetime.DateUtils;
22
import eu.dnetlib.miscutils.functional.hash.Hashing;
23
import eu.dnetlib.miscutils.functional.string.EscapeXml;
24
import eu.dnetlib.openaire.directindex.api.DirecIndexApiException;
25
import eu.dnetlib.openaire.directindex.api.OpenAIRESubmitterUtils;
26
import io.swagger.annotations.ApiModelProperty;
27

    
28
/**
29
 * Created by michele on 02/12/15.
30
 */
31
public class ResultEntry {
32

    
33
	private String openaireId;
34
	private String originalId;
35
	private String title;
36
	private List<String> authors = new ArrayList<>();
37
	private String publisher;
38
	private String description;
39
	private String language;
40
	private List<PidEntry> pids = new ArrayList<>();
41
	/**
42
	 * @Deprecated: use accessRightCode
43
	 */
44
	@Deprecated
45
	private String licenseCode;
46
	private String accessRightCode;
47
	private String embargoEndDate;
48
	/**
49
	 * One of publication, dataset, software, other. Default value is publication.
50
	 */
51
	private String type = "publication";
52
	private String resourceType;
53
	private String url;
54
	private String collectedFromId;
55
	private String hostedById;
56

    
57
	// String according to the EGI context profile, example: egi::classification::natsc::math
58
	private List<String> contexts = new ArrayList<>();
59

    
60
	// String according to openaire guidelines:
61
	// info:eu-repo/grantAgreement/Funder/FundingProgram/ProjectID/[Jurisdiction]/[ProjectName]/[ProjectAcronym]
62
	private List<String> linksToProjects = new ArrayList<>();
63

    
64
	private static long last_cache_update = 0;
65
	private static final Map<String, Map<String, String>> cached_vocabularies = new HashMap<>();
66
	private static final Map<String, DatasourceEntry> cached_datasources = new HashMap<>();
67
	private static final Map<String, String> cached_contexts = new HashMap<>();
68

    
69
	private static final Log log = LogFactory.getLog(ResultEntry.class);
70

    
71
	public ResultEntry() {}
72

    
73
	public String getOpenaireId() {
74
		return openaireId;
75
	}
76

    
77
	public void setOpenaireId(final String openaireId) {
78
		this.openaireId = openaireId;
79
	}
80

    
81
	public String getOriginalId() {
82
		return originalId;
83
	}
84

    
85
	public void setOriginalId(final String originalId) {
86
		this.originalId = originalId;
87
	}
88

    
89
	@ApiModelProperty(required = true)
90
	public String getTitle() {
91
		return title;
92
	}
93

    
94
	public void setTitle(final String title) {
95
		this.title = title;
96
	}
97

    
98
	public List<String> getAuthors() {
99
		return authors;
100
	}
101

    
102
	public void setAuthors(final List<String> authors) {
103
		this.authors = authors;
104
	}
105

    
106
	public String getPublisher() {
107
		return publisher;
108
	}
109

    
110
	public void setPublisher(final String publisher) {
111
		this.publisher = publisher;
112
	}
113

    
114
	public String getDescription() {
115
		return description;
116
	}
117

    
118
	public void setDescription(final String description) {
119
		this.description = description;
120
	}
121

    
122
	@ApiModelProperty(value = "ISO Alpha-3 code. E.g. 'eng', 'ita'")
123
	public String getLanguage() {
124
		return language;
125
	}
126

    
127
	public void setLanguage(final String language) {
128
		this.language = language;
129
	}
130

    
131
	public List<PidEntry> getPids() {
132
		return pids;
133
	}
134

    
135
	public void setPids(final List<PidEntry> pids) {
136
		this.pids = pids;
137
	}
138

    
139
	@Deprecated
140
	@ApiModelProperty(required = false, allowableValues = "OPEN, CLOSED, RESTRICTED, EMBARGO, UNKNOWN, OTHER, OPEN SOURCE")
141
	public String getLicenseCode() {
142
		return licenseCode;
143
	}
144
	@Deprecated
145
	public void setLicenseCode(final String licenseCode) {
146
		this.licenseCode = licenseCode;
147
	}
148

    
149
	/**
150
	 * Set required = true when the deprecated licenseCode is not used anymore by our client and it is removed
151
	 * @return
152
	 */
153
	@ApiModelProperty(required = false, allowableValues = "OPEN, CLOSED, RESTRICTED, EMBARGO, UNKNOWN, OTHER, OPEN SOURCE")
154
	public String getAccessRightCode() {
155
		return accessRightCode;
156
	}
157

    
158
	public void setAccessRightCode(final String accessRightCode) {
159
		this.accessRightCode = accessRightCode;
160
	}
161

    
162
	@ApiModelProperty(required = true, value = "Use 001 for articles, 021 for datasets, 0029 for software. See: http://api.openaire.eu/vocabularies/dnet:publication_resource for all the available resource types.")
163
	public String getResourceType() {
164
		return resourceType;
165
	}
166

    
167
	public void setResourceType(final String resourceType) {
168
		this.resourceType = resourceType;
169
	}
170

    
171
	@ApiModelProperty(required = true)
172
	public String getUrl() {
173
		return url;
174
	}
175

    
176
	public void setUrl(final String url) {
177
		this.url = url;
178
	}
179

    
180
	@ApiModelProperty(required = true, value = "Use opendoar___::2659 for Zenodo Publications; re3data_____::r3d100010468 for Zenodo datasets; infrastruct::openaire for OpenAIRE portal.")
181
	public String getCollectedFromId() {
182
		return collectedFromId;
183
	}
184

    
185
	public void setCollectedFromId(final String collectedFromId) {
186
		this.collectedFromId = collectedFromId;
187
	}
188

    
189
	public String getHostedById() {
190
		return hostedById;
191
	}
192

    
193
	public void setHostedById(final String hostedById) {
194
		this.hostedById = hostedById;
195
	}
196

    
197
	@ApiModelProperty(value = "E.g. fet, egi::classification::natsc::math::pure, egi::projects::EMI")
198
	public List<String> getContexts() {
199
		return contexts;
200
	}
201

    
202
	public void setContexts(final List<String> contexts) {
203
		this.contexts = contexts;
204
	}
205

    
206
	@ApiModelProperty(value = "E.g. info:eu-repo/grantAgreement/EC/FP7/283595/EU//OpenAIREplus")
207
	public List<String> getLinksToProjects() {
208
		return linksToProjects;
209
	}
210

    
211
	public void setLinksToProjects(final List<String> linksToProjects) {
212
		this.linksToProjects = linksToProjects;
213
	}
214

    
215
	@ApiModelProperty(allowableValues = "publication, dataset, software, other")
216
	public String getType() {
217
		return type;
218
	}
219

    
220
	public void setType(final String type) {
221
		this.type = type;
222
	}
223

    
224
	public String getEmbargoEndDate() {
225
		return embargoEndDate;
226
	}
227

    
228
	public void setEmbargoEndDate(final String embargoEndDate) {
229
		this.embargoEndDate = embargoEndDate;
230
	}
231

    
232
	public String asOafRecord(final VelocityEngine ve,
233
			final ISLookUpService lookupService,
234
			final String oafSchemaLocation) throws Exception {
235

    
236
		if (StringUtils.isBlank(getOriginalId())
237
				&& StringUtils
238
						.isBlank(getOpenaireId())) { throw new DirecIndexApiException("One of the following fields is required: originalId or openaireId"); }
239
		if (StringUtils.isBlank(getTitle())) { throw new DirecIndexApiException("A required field is missing: title"); }
240
		if (StringUtils.isBlank(getUrl())) { throw new DirecIndexApiException("A required field is missing: url"); }
241
		if (StringUtils.isBlank(getLicenseCode()) && StringUtils.isBlank(getAccessRightCode())) { throw new DirecIndexApiException("A required field is missing: accessRightCode"); }
242
		if (StringUtils.isBlank(getResourceType())) { throw new DirecIndexApiException("A required field is missing: resourceType"); }
243
		if (StringUtils.isBlank(getCollectedFromId())) { throw new DirecIndexApiException("A required field is missing: collectedFromId"); }
244
		if (StringUtils.isBlank(getType())) { throw new DirecIndexApiException("A required field is missing: type"); }
245

    
246
		final DatasourceEntry collectedFromEntry = getDatasourceInfo(collectedFromId, lookupService);
247
		final DatasourceEntry hostedByEntry = getDatasourceInfo(hostedById, lookupService);
248

    
249
		if (StringUtils.isBlank(openaireId)) {
250
			setOpenaireId(calculateOpenaireId(originalId, collectedFromEntry));
251
		}
252

    
253
		if (!openaireId
254
				.matches("^\\w{12}::\\w{32}$")) { throw new DirecIndexApiException(
255
						"Invalid openaireId: " + openaireId + " - regex ^\\w{12}::\\w{32}$ not matched"); }
256

    
257
		final Map<String, Object> model = new HashMap<>();
258
		model.put("esc", new EscapeXml());
259
		model.put("util", new OpenAIRESubmitterUtils());
260
		model.put("pub", this);
261
		model.put("objIdentifier", getOpenaireId());
262
		model.put("oafSchemaLocation", oafSchemaLocation);
263
		model.put("resultTypes", getVocabulary("dnet:result_typologies", lookupService));
264
		model.put("rights", getVocabulary("dnet:access_modes", lookupService));
265
		model.put("resourceTypes", getVocabulary("dnet:publication_resource", lookupService));
266
		model.put("pidTypes", getVocabulary("dnet:pid_types", lookupService));
267
		model.put("languages", getVocabulary("dnet:languages", lookupService));
268
		model.put("contexts", getContexts(lookupService));
269
		model.put("dateOfCollection", new SimpleDateFormat("yyyy-MM-dd\'T\'hh:mm:ss\'Z\'").format(new Date()));
270
		model.put("collectedFrom", collectedFromEntry);
271
		model.put("hostedBy", hostedByEntry);
272

    
273
		return VelocityEngineUtils.mergeTemplateIntoString(ve, "/eu/dnetlib/openaire/directindex/indexRecord.xml.vm", "UTF-8", model);
274
	}
275

    
276
	private static String calculateOpenaireId(final String originalId, final DatasourceEntry collectedFromEntry) {
277
		return collectedFromEntry.getPrefix() + "::" + Hashing.md5(originalId);
278
	}
279

    
280
	public static String calculateOpenaireId(final String originalId, final String collectedFromId, final ISLookUpService lookupService)
281
			throws ISLookUpException {
282
		return calculateOpenaireId(originalId, getDatasourceInfo(collectedFromId, lookupService));
283
	}
284

    
285
	private synchronized static DatasourceEntry getDatasourceInfo(final String dsId, final ISLookUpService lookupService) throws ISLookUpException {
286
		if (StringUtils
287
				.isBlank(dsId)) { return new DatasourceEntry("openaire____::1256f046-bf1f-4afc-8b47-d0b147148b18", "Unknown Repository", "unknown_____"); }
288

    
289
		if (!cached_datasources.containsKey(dsId)) {
290
			final String query =
291
					"collection('/db/DRIVER/RepositoryServiceResources/RepositoryServiceResourceType')//CONFIGURATION[./DATASOURCE_ORIGINAL_ID='" + dsId
292
							+ "']/concat(./OFFICIAL_NAME, ' @@@ ', .//FIELD/value[../key='NamespacePrefix'])";
293
			final String s = lookupService.getResourceProfileByQuery(query);
294
			final String[] arr = s.split("@@@");
295

    
296
			final DatasourceEntry ds = new DatasourceEntry(dsId, arr[0].trim(), arr[1].trim());
297

    
298
			if (StringUtils.isBlank(ds.getName()) || StringUtils.isBlank(ds.getPrefix())) {
299
				log.error("Invalid datasource id: " + dsId);
300
				throw new ISLookUpException("Invalid datasource id: " + dsId);
301
			} else {
302
				cached_datasources.put(dsId, ds);
303
			}
304
		}
305

    
306
		return cached_datasources.get(dsId);
307

    
308
	}
309

    
310
	private synchronized static Map<String, String> getVocabulary(final String voc, final ISLookUpService lookupService) throws ISLookUpException {
311

    
312
		if (DateUtils.now() - last_cache_update < TimeUnit.MINUTES.toMillis(15) && cached_vocabularies.containsKey(voc)) {
313
			return cached_vocabularies.get(voc);
314
		} else {
315
			final String query = "collection('/db/DRIVER/VocabularyDSResources/VocabularyDSResourceType')[.//VOCABULARY_NAME/@code='" + voc
316
					+ "']//TERM/concat(@code, ' @@@ ', @english_name)";
317

    
318
			final Map<String, String> map = new HashMap<>();
319
			for (final String s : lookupService.quickSearchProfile(query)) {
320
				final String[] arr = s.split("@@@");
321
				map.put(arr[0].trim(), arr[1].trim());
322
			}
323

    
324
			cached_vocabularies.put(voc, map);
325

    
326
			last_cache_update = DateUtils.now();
327

    
328
			return map;
329
		}
330
	}
331

    
332
	private synchronized static Map<String, String> getContexts(final ISLookUpService lookupService) throws ISLookUpException {
333
		if (DateUtils.now() - last_cache_update > TimeUnit.MINUTES.toMillis(15) || cached_contexts.isEmpty()) {
334
			final String query =
335
					"collection('/db/DRIVER/ContextDSResources/ContextDSResourceType')[.//context/@type='community' or .//context/@type='ri']//*[name()='context' or name()='category' or name()='concept']/concat(@id, ' @@@ ', @label)";
336

    
337
			cached_contexts.clear();
338
			for (final String s : lookupService.quickSearchProfile(query)) {
339
				final String[] arr = s.split("@@@");
340
				cached_contexts.put(arr[0].trim(), arr[1].trim());
341
			}
342
			last_cache_update = DateUtils.now();
343
		}
344
		return cached_contexts;
345
	}
346

    
347
	@Override
348
	public String toString() {
349
		return new Gson().toJson(this);
350
	}
351

    
352
	public String getAnyId() {
353
		return StringUtils.isNotBlank(openaireId) ? openaireId : originalId;
354
	}
355
}
(3-3/3)