Project

General

Profile

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
}
(5-5/5)