1
|
package eu.dnetlib.parthenos.catalogue;
|
2
|
|
3
|
import java.io.BufferedOutputStream;
|
4
|
import java.io.ByteArrayOutputStream;
|
5
|
import java.io.IOException;
|
6
|
import java.net.URISyntaxException;
|
7
|
import java.util.Iterator;
|
8
|
|
9
|
import com.fasterxml.jackson.core.JsonEncoding;
|
10
|
import com.fasterxml.jackson.core.JsonFactory;
|
11
|
import com.fasterxml.jackson.core.JsonGenerator;
|
12
|
import com.google.common.base.Joiner;
|
13
|
import eu.dnetlib.parthenos.jrr.ParthenosRegistryResource;
|
14
|
import eu.dnetlib.parthenos.publisher.ParthenosPublisherException;
|
15
|
import eu.dnetlib.parthenos.rdf.ResourceReader;
|
16
|
import org.apache.commons.lang3.StringUtils;
|
17
|
import org.apache.commons.logging.Log;
|
18
|
import org.apache.commons.logging.LogFactory;
|
19
|
import org.apache.jena.rdf.model.Resource;
|
20
|
import org.springframework.beans.factory.annotation.Autowired;
|
21
|
import org.springframework.stereotype.Component;
|
22
|
|
23
|
import static eu.dnetlib.parthenos.CRM.*;
|
24
|
|
25
|
/**
|
26
|
* Created by Alessia Bardi on 21/11/2017.
|
27
|
*
|
28
|
* @author Alessia Bardi
|
29
|
*/
|
30
|
@Component
|
31
|
public class CatalogueRegistrator {
|
32
|
|
33
|
private static final Log log = LogFactory.getLog(CatalogueRegistrator.class);
|
34
|
private final String PARTHENOS_BASE_URL = "http://parthenos.d4science.org";
|
35
|
|
36
|
@Autowired
|
37
|
private ResourceReader resourceReader;
|
38
|
|
39
|
@Autowired
|
40
|
private CatalogueAPIClient catalogueAPIClient;
|
41
|
|
42
|
private String groupTemplate = "{"
|
43
|
+ " \"name\":\"%s\","
|
44
|
+ " \"id\":\"%s\","
|
45
|
+ " \"title\": \"%s\""
|
46
|
//+ " \"description\": \"%s\""
|
47
|
+ "}";
|
48
|
|
49
|
|
50
|
|
51
|
public String register(final Resource resource, final Resource type) throws IOException, ParthenosPublisherException, URISyntaxException {
|
52
|
String resURI = resource.getURI();
|
53
|
log.debug(String.format("Catalogue --> Processing resource : %s with type: %s", resURI, type.getLocalName()));
|
54
|
//For the catalogue: Must be purely lowercase alphanumeric (ascii) characters and these symbols: -_
|
55
|
//Replacing all non-alphanumeric characters with empty strings
|
56
|
String resCatName = resURI.substring(resURI.lastIndexOf("/") + 1).replaceAll("[^A-Za-z0-9]","_").toLowerCase();
|
57
|
ParthenosRegistryResource prr = catalogueAPIClient.getRegistered(resCatName);
|
58
|
if(prr != null){
|
59
|
//TODO: what to do if already registered?
|
60
|
return prr.getUuid();
|
61
|
}
|
62
|
else {
|
63
|
//resource not yet registered
|
64
|
ensureGroups(resource);
|
65
|
String json;
|
66
|
switch (type.getLocalName()) {
|
67
|
case "E7_Activity":
|
68
|
json = getJsonForActivity(resource, resCatName);
|
69
|
break;
|
70
|
case "E39_Actor":
|
71
|
json = getJsonForActor(resource, resCatName);
|
72
|
break;
|
73
|
case "E70_Thing":
|
74
|
json = getJsonForThing(resource, resCatName);
|
75
|
break;
|
76
|
case "E55_Type":
|
77
|
json = getJsonForType(resource, resCatName);
|
78
|
break;
|
79
|
case "E29_Design_or_Procedure":
|
80
|
json = getJsonForDesignProcedure(resource, resCatName);
|
81
|
break;
|
82
|
//TODO: handle more types, see JRRPublisher
|
83
|
//CRM.E55_Type
|
84
|
//CRM.E29_Design_or_Procedure
|
85
|
default:
|
86
|
throw new IllegalArgumentException(String.format("Type " + type.getLocalName() + " not supported"));
|
87
|
}
|
88
|
String uuid = catalogueAPIClient.doRegister(json, resCatName);
|
89
|
log.debug(String.format("%s registered on the catalogue with uuid: %s", resURI, uuid));
|
90
|
return uuid;
|
91
|
}
|
92
|
|
93
|
}
|
94
|
|
95
|
|
96
|
|
97
|
|
98
|
protected boolean purge(final String resCatName) throws URISyntaxException, IOException {
|
99
|
return catalogueAPIClient.purgeItem(resCatName);
|
100
|
}
|
101
|
|
102
|
/**
|
103
|
* Ensure that providers referred in the Resource are available as "groups" in the registry.
|
104
|
* @param res Resource
|
105
|
*/
|
106
|
protected void ensureGroups(final Resource res) throws ParthenosPublisherException, IOException, URISyntaxException {
|
107
|
log.debug("Ensuring groups exist");
|
108
|
Iterator<String> providerNames = resourceReader.getProviderNames(res);
|
109
|
while(providerNames.hasNext()){
|
110
|
String name = providerNames.next();
|
111
|
if(StringUtils.isNotBlank(name)){
|
112
|
// the name of the group, a string between 2 and 100 characters long, containing only lowercase alphanumeric characters, - and _
|
113
|
String groupName = name.replaceAll("[^A-Za-z0-9]","_").toLowerCase();
|
114
|
if(groupName.length() > 100){
|
115
|
groupName = groupName.substring(0,99);
|
116
|
}
|
117
|
if(!catalogueAPIClient.groupExist(groupName)){
|
118
|
String groupJson = String.format(groupTemplate, groupName, groupName, name);
|
119
|
catalogueAPIClient.registerGroup(groupJson, groupName);
|
120
|
}
|
121
|
}
|
122
|
}
|
123
|
}
|
124
|
|
125
|
protected String getJsonForActivity(final Resource res, final String resNameForCatalogue) throws IOException {
|
126
|
JsonFactory jsonFactory = new JsonFactory();
|
127
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
128
|
BufferedOutputStream bos = new BufferedOutputStream(out);
|
129
|
JsonGenerator jg = jsonFactory.createGenerator(bos, JsonEncoding.UTF8);
|
130
|
jg.writeStartObject();
|
131
|
writeCommonFields(jg, res, resNameForCatalogue);
|
132
|
//TODO: from which linked E39_Actor?
|
133
|
//for project we can take it from the maintainer team: is this correct also for other Things (like Services and Software?)
|
134
|
jg.writeStringField("maintainer", Joiner.on(", ").join(resourceReader.getMaintainerUrls(res)));
|
135
|
//TODO: it should be better to identify email contacts rather than generic contact labels of maintainer
|
136
|
//jg.writeStringField("maintainer_email", Joiner.on(", ").join(resourceReader.getMaintainerContacts(res)));
|
137
|
|
138
|
jg.writeArrayFieldStart("extras");
|
139
|
addExtra(jg, "system:type", E7_Activity.getLocalName());
|
140
|
//specific class
|
141
|
addExtra(jg, "instance of", resourceReader.findSpecificType(res, E7_Activity).getLocalName());
|
142
|
if (res.getURI().startsWith(PARTHENOS_BASE_URL))
|
143
|
addExtra(jg, "Parthenos URL", res.getURI());
|
144
|
//for Services
|
145
|
addExtra(jg, "competence", resourceReader.getCompetence(res));
|
146
|
addExtra(jg, "provided by", Joiner.on(", ").join(resourceReader.getProviderNames(res)));
|
147
|
addExtra(jg, "declared begin/end of operation", Joiner.on(", ").join(resourceReader.getDeclarativeTimes(res)));
|
148
|
//TODO: where to get it?
|
149
|
addExtra(jg, "last confirmation", "");
|
150
|
//TODO: where to get it?
|
151
|
addExtra(jg, "date of registration", "");
|
152
|
addExtra(jg, "availability", resourceReader.getAvailability(res));
|
153
|
addExtra(jg, "condition of use", resourceReader.getConditionOfUse(res));
|
154
|
addExtra(jg, "contact points", Joiner.on(", ").join(resourceReader.getProviderContactPoints(res)));
|
155
|
addExtra(jg, "activity type", Joiner.on(", ").join(resourceReader.getActivityTypes(res)));
|
156
|
// can't add multiple fields with same name, hence skipping
|
157
|
addExtra(jg, "hosts", Joiner.on(", ").join(resourceReader.getHostedStuff(res)));
|
158
|
addExtra(jg, "online access point", Joiner.on(", ").join(resourceReader.getAccessPoints(res)));
|
159
|
//TODO: where to get it?
|
160
|
addExtra(jg, "authorization", "");
|
161
|
addExtra(jg, "protocol", Joiner.on(", ").join(resourceReader.getProtocols(res)));
|
162
|
addExtra(jg,"curates", Joiner.on(", ").join(resourceReader.getCuratedObjects(res)));
|
163
|
//TODO: where to get it?
|
164
|
addExtra(jg, "runs on request", "");
|
165
|
addExtra(jg, "delivers on request", Joiner.on(", ").join(resourceReader.getDeliversOnRequest(res)));
|
166
|
addExtra(jg, "uses curation plan", Joiner.on(", ").join(resourceReader.getCurationPlans(res)));
|
167
|
|
168
|
//for Projects
|
169
|
addExtra(jg, "offers", Joiner.on(", ").join(resourceReader.getOfferedServiceUrls(res)));
|
170
|
addExtra(jg, "started", Joiner.on(", ").join(resourceReader.getStartTimes(res)));
|
171
|
|
172
|
jg.writeEndArray(); //end extras
|
173
|
|
174
|
jg.writeEndObject();
|
175
|
jg.close();
|
176
|
return out.toString("UTF-8");
|
177
|
}
|
178
|
|
179
|
protected String getJsonForActor(final Resource res, final String resNameForCatalogue) throws IOException {
|
180
|
JsonFactory jsonFactory = new JsonFactory();
|
181
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
182
|
BufferedOutputStream bos = new BufferedOutputStream(out);
|
183
|
JsonGenerator jg = jsonFactory.createGenerator(bos, JsonEncoding.UTF8);
|
184
|
jg.writeStartObject();
|
185
|
writeCommonFields(jg, res, resNameForCatalogue);
|
186
|
|
187
|
jg.writeArrayFieldStart("extras");
|
188
|
addExtra(jg, "system:type", E39_Actor.getLocalName());
|
189
|
//specific class
|
190
|
addExtra(jg, "instance of", resourceReader.findSpecificType(res, E39_Actor).getLocalName());
|
191
|
if (res.getURI().startsWith(PARTHENOS_BASE_URL))
|
192
|
addExtra(jg, "Parthenos URL", res.getURI());
|
193
|
addExtra(jg, "has member", Joiner.on(", ").join(resourceReader.getMemberUrls(res)));
|
194
|
addExtra(jg, "is member of", Joiner.on(", ").join(resourceReader.isMemberOf(res)));
|
195
|
addExtra(jg, "has contact point", Joiner.on(", ").join(resourceReader.getResourceDirectContactPoints(res)));
|
196
|
addExtra(jg, "provides", Joiner.on(", ").join(resourceReader.getProvidedServiceUrls(res)));
|
197
|
jg.writeEndArray();
|
198
|
|
199
|
jg.writeEndObject();
|
200
|
jg.close();
|
201
|
return out.toString("UTF-8");
|
202
|
}
|
203
|
|
204
|
protected String getJsonForThing(final Resource res, final String resNameForCatalogue) throws IOException {
|
205
|
JsonFactory jsonFactory = new JsonFactory();
|
206
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
207
|
BufferedOutputStream bos = new BufferedOutputStream(out);
|
208
|
JsonGenerator jg = jsonFactory.createGenerator(bos, JsonEncoding.UTF8);
|
209
|
jg.writeStartObject();
|
210
|
writeCommonFields(jg, res, resNameForCatalogue);
|
211
|
|
212
|
jg.writeArrayFieldStart("extras");
|
213
|
addExtra(jg, "system:type", E70_Thing.getLocalName());
|
214
|
//specific class
|
215
|
addExtra(jg, "instance of", resourceReader.findSpecificType(res, E70_Thing).getLocalName());
|
216
|
if (res.getURI().startsWith(PARTHENOS_BASE_URL)) {
|
217
|
addExtra(jg, "Parthenos URL", res.getURI());
|
218
|
}
|
219
|
//TODO: things include digital objects, software, datasets, schema. Guess we should know what to add here.
|
220
|
addExtra(jg, "is part of", Joiner.on(", ").join(resourceReader.getIsPartOfUrls(res)));
|
221
|
addExtra(jg, "has part", Joiner.on(", ").join(resourceReader.getHasPartUrls(res)));
|
222
|
addExtra(jg, "curated by", Joiner.on(", ").join(resourceReader.getCuratorUrls(res)));
|
223
|
addExtra(jg, "curation plan", Joiner.on(", ").join(resourceReader.getCurationPlans(res)));
|
224
|
addExtra(jg, "hosted by", Joiner.on(", ").join(resourceReader.getHostedBys(res)));
|
225
|
//TODO where to get the encoding types? Should we through the Creation event?
|
226
|
//addExtra(jg, "encoding type", Joiner.on(", ").join());
|
227
|
//TODO where to get the schema/formats? Should we through the Creation event?
|
228
|
//addExtra(jg, "encoding type", Joiner.on(", ").join());
|
229
|
//TODO where to get the creator? Should we through the Creation event?
|
230
|
//addExtra(jg, "creator", Joiner.on(", ").join());
|
231
|
addExtra(jg, "subject", Joiner.on(", ").join(resourceReader.getSubjects(res)));
|
232
|
addExtra(jg, "temporal coverage", Joiner.on(", ").join(resourceReader.getTemporalCoverages(res)));
|
233
|
addExtra(jg, "spatial coverage", Joiner.on(", ").join(resourceReader.getSpatialCoverages(res)));
|
234
|
|
235
|
|
236
|
jg.writeEndArray();
|
237
|
|
238
|
jg.writeEndObject();
|
239
|
jg.close();
|
240
|
return out.toString("UTF-8");
|
241
|
}
|
242
|
|
243
|
protected String getJsonForType(final Resource res, final String resNameForCatalogue) throws IOException {
|
244
|
JsonFactory jsonFactory = new JsonFactory();
|
245
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
246
|
BufferedOutputStream bos = new BufferedOutputStream(out);
|
247
|
JsonGenerator jg = jsonFactory.createGenerator(bos, JsonEncoding.UTF8);
|
248
|
jg.writeStartObject();
|
249
|
writeCommonFields(jg, res, resNameForCatalogue);
|
250
|
|
251
|
jg.writeArrayFieldStart("extras");
|
252
|
addExtra(jg, "system:type", E55_Type.getLocalName());
|
253
|
//specific class
|
254
|
addExtra(jg, "instance of", resourceReader.findSpecificType(res, E55_Type).getLocalName());
|
255
|
if (res.getURI().startsWith(PARTHENOS_BASE_URL)) {
|
256
|
addExtra(jg, "Parthenos URL", res.getURI());
|
257
|
}
|
258
|
//TODO: add additional metadata for Type, if any
|
259
|
jg.writeEndArray();
|
260
|
|
261
|
jg.writeEndObject();
|
262
|
jg.close();
|
263
|
return out.toString("UTF-8");
|
264
|
}
|
265
|
|
266
|
protected String getJsonForDesignProcedure(final Resource res, final String resNameForCatalogue) throws IOException {
|
267
|
JsonFactory jsonFactory = new JsonFactory();
|
268
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
269
|
BufferedOutputStream bos = new BufferedOutputStream(out);
|
270
|
JsonGenerator jg = jsonFactory.createGenerator(bos, JsonEncoding.UTF8);
|
271
|
jg.writeStartObject();
|
272
|
writeCommonFields(jg, res, resNameForCatalogue);
|
273
|
|
274
|
jg.writeArrayFieldStart("extras");
|
275
|
addExtra(jg, "system:type", E29_Design_or_Procedure.getLocalName());
|
276
|
//specific class
|
277
|
addExtra(jg, "instance of", resourceReader.findSpecificType(res, E29_Design_or_Procedure).getLocalName());
|
278
|
if (res.getURI().startsWith(PARTHENOS_BASE_URL)) {
|
279
|
addExtra(jg, "Parthenos URL", res.getURI());
|
280
|
}
|
281
|
//TODO: add additional metadata for E29_Design_or_Procedure, if any
|
282
|
jg.writeEndArray();
|
283
|
|
284
|
jg.writeEndObject();
|
285
|
jg.close();
|
286
|
return out.toString("UTF-8");
|
287
|
}
|
288
|
|
289
|
protected void addExtra(final JsonGenerator jg, final String key, final String value) throws IOException {
|
290
|
jg.writeStartObject();
|
291
|
jg.writeStringField("key", key);
|
292
|
jg.writeStringField("value", value);
|
293
|
jg.writeEndObject();
|
294
|
}
|
295
|
|
296
|
protected void writeCommonFields(final JsonGenerator jg, final Resource res, final String resNameForCatalogue) throws IOException {
|
297
|
//end of URI
|
298
|
jg.writeStringField("name", resNameForCatalogue);
|
299
|
//default license
|
300
|
jg.writeStringField("license_id", "notspecified");
|
301
|
String title = resourceReader.getTitle(res);
|
302
|
if (StringUtils.isBlank(title))
|
303
|
title = resNameForCatalogue;
|
304
|
jg.writeStringField("title", title);
|
305
|
//description
|
306
|
jg.writeStringField("notes", resourceReader.getDescription(res));
|
307
|
//the names of all superclasses of the entity
|
308
|
jg.writeArrayFieldStart("tags");
|
309
|
Iterator<String> classNames = resourceReader.getRDFClassNames(res);
|
310
|
while (classNames.hasNext()) {
|
311
|
jg.writeStartObject();
|
312
|
jg.writeStringField("name", classNames.next());
|
313
|
jg.writeEndObject();
|
314
|
}
|
315
|
jg.writeEndArray();
|
316
|
//RI from which the entity has been collected, the source from which the RI collected the entity (if available).
|
317
|
//TODO: other Actors to add as catalogue group?
|
318
|
Iterator<String> providers = resourceReader.getProviderNames(res);
|
319
|
jg.writeArrayFieldStart("groups");
|
320
|
while(providers.hasNext()){
|
321
|
String provider = providers.next();
|
322
|
jg.writeStartObject();
|
323
|
jg.writeStringField("name", provider);
|
324
|
jg.writeEndObject();
|
325
|
}
|
326
|
jg.writeEndArray();
|
327
|
}
|
328
|
|
329
|
|
330
|
public ResourceReader getResourceReader() {
|
331
|
return resourceReader;
|
332
|
}
|
333
|
|
334
|
public void setResourceReader(final ResourceReader resourceReader) {
|
335
|
this.resourceReader = resourceReader;
|
336
|
}
|
337
|
|
338
|
public CatalogueAPIClient getCatalogueAPIClient() {
|
339
|
return catalogueAPIClient;
|
340
|
}
|
341
|
|
342
|
public void setCatalogueAPIClient(final CatalogueAPIClient catalogueAPIClient) {
|
343
|
this.catalogueAPIClient = catalogueAPIClient;
|
344
|
}
|
345
|
}
|