Project

General

Profile

1
package eu.dnetlib.msro.openaireplus.api.objects;
2

    
3
import java.text.SimpleDateFormat;
4
import java.util.*;
5
import java.util.concurrent.TimeUnit;
6

    
7
import com.google.gson.Gson;
8
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
9
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
10
import eu.dnetlib.miscutils.datetime.DateUtils;
11
import eu.dnetlib.miscutils.functional.hash.Hashing;
12
import eu.dnetlib.miscutils.functional.string.EscapeXml;
13
import eu.dnetlib.msro.openaireplus.api.OpenAIRESubmitterUtils;
14
import eu.dnetlib.msro.rmi.MSROException;
15
import io.swagger.annotations.ApiModelProperty;
16
import org.apache.commons.lang.StringUtils;
17
import org.apache.commons.logging.Log;
18
import org.apache.commons.logging.LogFactory;
19
import org.apache.velocity.app.VelocityEngine;
20
import org.springframework.ui.velocity.VelocityEngineUtils;
21

    
22
/**
23
 * Created by michele on 02/12/15.
24
 */
25
public class ResultEntry {
26

    
27
	private String openaireId;
28
	private String originalId;
29
	private String title;
30
	private List<String> authors = new ArrayList<String>();
31
	private String publisher;
32
	private String description;
33
	private String language;
34
	private List<PidEntry> pids = new ArrayList<PidEntry>();
35
	private String licenseCode;
36
	private String embargoEndDate;
37
	private String type = "publication";
38
	private String resourceType;
39
	private String url;
40
	private String collectedFromId;
41
	private String hostedById;
42

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

    
46
	// String according to openaire guidelines:
47
	// info:eu-repo/grantAgreement/Funder/FundingProgram/ProjectID/[Jurisdiction]/[ProjectName]/[ProjectAcronym]
48
	private List<String> linksToProjects = new ArrayList<String>();
49

    
50
	private static long last_cache_update = 0;
51
	private static final Map<String, Map<String, String>> cached_vocabularies = new HashMap<String, Map<String, String>>();
52
	private static final Map<String, DatasourceEntry> cached_datasources = new HashMap<String, DatasourceEntry>();
53
	private static final Map<String, String> cached_contexts = new HashMap<String, String>();
54

    
55
	private static final Log log = LogFactory.getLog(ResultEntry.class);
56

    
57
	public ResultEntry() {
58
	}
59

    
60
	public String getOpenaireId() {
61
		return openaireId;
62
	}
63

    
64
	public void setOpenaireId(String openaireId) {
65
		this.openaireId = openaireId;
66
	}
67

    
68
	public String getOriginalId() {
69
		return originalId;
70
	}
71

    
72
	public void setOriginalId(final String originalId) {
73
		this.originalId = originalId;
74
	}
75

    
76
	@ApiModelProperty(required = true)
77
	public String getTitle() {
78
		return title;
79
	}
80

    
81
	public void setTitle(final String title) {
82
		this.title = title;
83
	}
84

    
85
	public List<String> getAuthors() {
86
		return authors;
87
	}
88

    
89
	public void setAuthors(final List<String> authors) {
90
		this.authors = authors;
91
	}
92

    
93
	public String getPublisher() {
94
		return publisher;
95
	}
96

    
97
	public void setPublisher(final String publisher) {
98
		this.publisher = publisher;
99
	}
100

    
101
	public String getDescription() {
102
		return description;
103
	}
104

    
105
	public void setDescription(final String description) {
106
		this.description = description;
107
	}
108

    
109
	@ApiModelProperty(value = "ISO Alpha-3 code. E.g. 'eng', 'ita'")
110
	public String getLanguage() {
111
		return language;
112
	}
113

    
114
	public void setLanguage(final String language) {
115
		this.language = language;
116
	}
117

    
118
	public List<PidEntry> getPids() {
119
		return pids;
120
	}
121

    
122
	public void setPids(final List<PidEntry> pids) {
123
		this.pids = pids;
124
	}
125

    
126
	@ApiModelProperty(required = true, allowableValues = "OPEN, CLOSED, RESTRICTED, EMBARGO, UNKNOWN, OTHER")
127
	public String getLicenseCode() {
128
		return licenseCode;
129
	}
130

    
131
	public void setLicenseCode(final String licenseCode) {
132
		this.licenseCode = licenseCode;
133
	}
134

    
135
	@ApiModelProperty(required = true, value = "Use 001 for articles, 021 for datasets. See: http://api.openaire.eu/vocabularies/dnet:publication_resource.")
136
	public String getResourceType() {
137
		return resourceType;
138
	}
139

    
140
	public void setResourceType(final String resourceType) {
141
		this.resourceType = resourceType;
142
	}
143

    
144
	@ApiModelProperty(required = true)
145
	public String getUrl() {
146
		return url;
147
	}
148

    
149
	public void setUrl(final String url) {
150
		this.url = url;
151
	}
152

    
153
	@ApiModelProperty(required = true, value = "Use opendoar___::2659 for Zenodo Publications; re3data_____::r3d100010468 for Zenodo datasets; infrastruct::openaire for OpenAIRE portal.")
154
	public String getCollectedFromId() {
155
		return collectedFromId;
156
	}
157

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

    
162
	public String getHostedById() {
163
		return hostedById;
164
	}
165

    
166
	public void setHostedById(final String hostedById) {
167
		this.hostedById = hostedById;
168
	}
169

    
170
	@ApiModelProperty(value = "E.g. fet, egi::classification::natsc::math::pure, egi::projects::EMI")
171
	public List<String> getContexts() {
172
		return contexts;
173
	}
174

    
175
	public void setContexts(final List<String> contexts) {
176
		this.contexts = contexts;
177
	}
178

    
179
	@ApiModelProperty(value = "E.g. info:eu-repo/grantAgreement/EC/FP7/283595/EU//OpenAIREplus")
180
	public List<String> getLinksToProjects() {
181
		return linksToProjects;
182
	}
183

    
184
	public void setLinksToProjects(final List<String> linksToProjects) {
185
		this.linksToProjects = linksToProjects;
186
	}
187

    
188
	@ApiModelProperty(allowableValues = "publication, dataset")
189
	public String getType() {
190
		return type;
191
	}
192

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

    
197
	public String getEmbargoEndDate() {
198
		return embargoEndDate;
199
	}
200

    
201
	public void setEmbargoEndDate(final String embargoEndDate) {
202
		this.embargoEndDate = embargoEndDate;
203
	}
204

    
205
	public String asOafRecord(final VelocityEngine ve,
206
			final ISLookUpService lookupService,
207
			final String oafSchemaLocation) throws Exception {
208

    
209
		if (StringUtils.isBlank(getOriginalId()) && StringUtils.isBlank(getOpenaireId())) {
210
			throw new MSROException("One of the following fields is required: originalId or openaireId");
211
		}
212
		if (StringUtils.isBlank(getTitle())) { throw new MSROException("A required field is missing: title"); }
213
		if (StringUtils.isBlank(getUrl())) { throw new MSROException("A required field is missing: url"); }
214
		if (StringUtils.isBlank(getLicenseCode())) { throw new MSROException("A required field is missing: licenseCode"); }
215
		if (StringUtils.isBlank(getResourceType())) { throw new MSROException("A required field is missing: resourceType"); }
216
		if (StringUtils.isBlank(getCollectedFromId())) { throw new MSROException("A required field is missing: collectedFromId"); }
217
		if (StringUtils.isBlank(getType())) { throw new MSROException("A required field is missing: type"); }
218

    
219
		final DatasourceEntry collectedFromEntry = getDatasourceInfo(collectedFromId, lookupService);
220
		final DatasourceEntry hostedByEntry = getDatasourceInfo(hostedById, lookupService);
221

    
222
		if (StringUtils.isBlank(openaireId)) {
223
			setOpenaireId(calculateOpenaireId(originalId, collectedFromEntry));
224
		}
225

    
226
		if (!openaireId.matches("^\\w{12}::\\w{32}$")) {
227
			throw new MSROException("Invalid openaireId: " + openaireId + " - regex ^\\w{12}::\\w{32}$ not matched");
228
		}
229

    
230
		final Map<String, Object> model = new HashMap<String, Object>();
231
		model.put("esc", new EscapeXml());
232
		model.put("util", new OpenAIRESubmitterUtils());
233
		model.put("pub", this);
234
		model.put("objIdentifier", getOpenaireId());
235
		model.put("oafSchemaLocation", oafSchemaLocation);
236
		model.put("resultTypes", getVocabulary("dnet:result_typologies", lookupService));
237
		model.put("licenses", getVocabulary("dnet:access_modes", lookupService));
238
		model.put("resourceTypes", getVocabulary("dnet:publication_resource", lookupService));
239
		model.put("pidTypes", getVocabulary("dnet:pid_types", lookupService));
240
		model.put("languages", getVocabulary("dnet:languages", lookupService));
241
		model.put("contexts", getContexts(lookupService));
242
		model.put("dateOfCollection", (new SimpleDateFormat("yyyy-MM-dd\'T\'hh:mm:ss\'Z\'")).format(new Date()));
243
		model.put("collectedFrom", collectedFromEntry);
244
		model.put("hostedBy", hostedByEntry);
245

    
246
		return VelocityEngineUtils.mergeTemplateIntoString(ve, "/eu/dnetlib/msro/openaireplus/api/indexRecord.xml.vm", "UTF-8", model);
247
	}
248

    
249
	private static String calculateOpenaireId(final String originalId, final DatasourceEntry collectedFromEntry) {
250
		return collectedFromEntry.getPrefix() + "::" + Hashing.md5(originalId);
251
	}
252

    
253
	public static String calculateOpenaireId(final String originalId, final String collectedFromId, final ISLookUpService lookupService)
254
			throws ISLookUpException {
255
		return calculateOpenaireId(originalId, getDatasourceInfo(collectedFromId, lookupService));
256
	}
257

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

    
262
		if (!cached_datasources.containsKey(dsId)) {
263
			final String query =
264
					"collection('/db/DRIVER/RepositoryServiceResources/RepositoryServiceResourceType')//CONFIGURATION[./DATASOURCE_ORIGINAL_ID='" + dsId
265
							+ "']/concat(./OFFICIAL_NAME, ' @@@ ', .//FIELD/value[../key='NamespacePrefix'])";
266
			final String s = lookupService.getResourceProfileByQuery(query);
267
			final String[] arr = s.split("@@@");
268

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

    
271
			if (StringUtils.isBlank(ds.getName()) || StringUtils.isBlank(ds.getPrefix())) {
272
				log.error("Invalid datasource id: " + dsId);
273
				throw new ISLookUpException("Invalid datasource id: " + dsId);
274
			} else {
275
				cached_datasources.put(dsId, ds);
276
			}
277
		}
278

    
279
		return cached_datasources.get(dsId);
280

    
281
	}
282

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

    
285
		if (((DateUtils.now() - last_cache_update) < TimeUnit.MINUTES.toMillis(15)) && cached_vocabularies.containsKey(voc)) {
286
			return cached_vocabularies.get(voc);
287
		} else {
288
			final String query = "collection('/db/DRIVER/VocabularyDSResources/VocabularyDSResourceType')[.//VOCABULARY_NAME/@code='" + voc
289
					+ "']//TERM/concat(@code, ' @@@ ', @english_name)";
290

    
291
			final Map<String, String> map = new HashMap<String, String>();
292
			for (final String s : lookupService.quickSearchProfile(query)) {
293
				final String[] arr = s.split("@@@");
294
				map.put(arr[0].trim(), arr[1].trim());
295
			}
296

    
297
			cached_vocabularies.put(voc, map);
298

    
299
			last_cache_update = DateUtils.now();
300

    
301
			return map;
302
		}
303
	}
304

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

    
310
			cached_contexts.clear();
311
			for (final String s : lookupService.quickSearchProfile(query)) {
312
				final String[] arr = s.split("@@@");
313
				cached_contexts.put(arr[0].trim(), arr[1].trim());
314
			}
315
			last_cache_update = DateUtils.now();
316
		}
317
		return cached_contexts;
318
	}
319

    
320
	@Override
321
	public String toString() {
322
		return new Gson().toJson(this);
323
	}
324

    
325
	public String getAnyId(){
326
		return StringUtils.isNotBlank(openaireId) ? openaireId : originalId;
327
	}
328
}
(3-3/3)