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
		String resCatName = resURI.substring(resURI.lastIndexOf("/") + 1).toLowerCase();
56
		ParthenosRegistryResource prr = catalogueAPIClient.getRegistered(resCatName);
57
		if(prr != null){
58
			//TODO: what to do if already registered?
59
			return prr.getUuid();
60
		}
61
		else {
62
			//resource not yet registered
63
			ensureGroups(resource);
64
			String json;
65
			switch (type.getLocalName()) {
66
			case "E7_Activity":
67
				json = getJsonForActivity(resource, resCatName);
68
				break;
69
			case "E39_Actor":
70
				json = getJsonForActor(resource, resCatName);
71
				break;
72
			case "E70_Thing":
73
				json = getJsonForThing(resource, resCatName);
74
				break;
75
			//TODO: handle more types, see JRRPublisher
76
			//CRM.E55_Type
77
			//CRM.E29_Design_or_Procedure
78
			default:
79
				throw new IllegalArgumentException(String.format("Type " + type.getLocalName() + " not supported"));
80
			}
81
			String uuid = catalogueAPIClient.doRegister(json, resCatName);
82
			log.debug(String.format("%s registered on the catalogue with uuid: %s", resURI, uuid));
83
			return uuid;
84
		}
85

    
86
	}
87

    
88
	protected boolean purge(final String resCatName) throws URISyntaxException, IOException {
89
		return catalogueAPIClient.purgeItem(resCatName);
90
	}
91

    
92
	/**
93
	 * Ensure that providers referred in the Resource are available as "groups" in the registry.
94
	 * @param res Resource
95
	 */
96
	protected void ensureGroups(final Resource res) throws ParthenosPublisherException, IOException, URISyntaxException {
97
		log.debug("Ensuring groups exist");
98
		Iterator<String> providerNames = resourceReader.getProviderNames(res);
99
		while(providerNames.hasNext()){
100
			String name = providerNames.next();
101
			if(StringUtils.isNotBlank(name)){
102
				// the name of the group, a string between 2 and 100 characters long, containing only lowercase alphanumeric characters, - and _
103
				String groupName = name.replaceAll(" ","_").toLowerCase();
104
				if(groupName.length() > 100){
105
					groupName = groupName.substring(0,99);
106
				}
107
				if(!catalogueAPIClient.groupExist(groupName)){
108
					String groupJson = String.format(groupTemplate, groupName, groupName, name);
109
					catalogueAPIClient.registerGroup(groupJson, groupName);
110
				}
111
			}
112
		}
113
	}
114

    
115
	protected String getJsonForActivity(final Resource res, final String resNameForCatalogue) throws IOException {
116
		JsonFactory jsonFactory = new JsonFactory();
117
		final ByteArrayOutputStream out = new ByteArrayOutputStream();
118
		BufferedOutputStream bos = new BufferedOutputStream(out);
119
		JsonGenerator jg = jsonFactory.createGenerator(bos, JsonEncoding.UTF8);
120
		jg.writeStartObject();
121
		writeCommonFields(jg, res, resNameForCatalogue);
122
		//TODO: from which linked E39_Actor?
123
		//for project we can take it from the maintainer team: is this correct also for other Things (like Services and Software?)
124
		jg.writeStringField("maintainer", Joiner.on(", ").join(resourceReader.getMaintainerUrls(res)));
125
		//TODO: it should be better to identify email contacts rather than generic contact labels of maintainer
126
		//jg.writeStringField("maintainer_email", Joiner.on(", ").join(resourceReader.getMaintainerContacts(res)));
127

    
128
		jg.writeArrayFieldStart("extras");
129
		addExtra(jg, "system:type", E7_Activity.getLocalName());
130
		//specific class
131
		addExtra(jg, "instance of", resourceReader.findSpecificType(res, E7_Activity).getLocalName());
132
		if (res.getURI().startsWith(PARTHENOS_BASE_URL))
133
			addExtra(jg, "Parthenos URL", res.getURI());
134
		//for Services
135
		addExtra(jg, "competence", resourceReader.getCompetence(res));
136
		addExtra(jg, "provided by", Joiner.on(", ").join(resourceReader.getProviderNames(res)));
137
		addExtra(jg, "declared begin/end of operation", Joiner.on(", ").join(resourceReader.getDeclarativeTimes(res)));
138
		//TODO: where to get it?
139
		addExtra(jg, "last confirmation", "");
140
		//TODO: where to get it?
141
		addExtra(jg, "date of registration", "");
142
		addExtra(jg, "availability", resourceReader.getAvailability(res));
143
		addExtra(jg, "condition of use", resourceReader.getConditionOfUse(res));
144
		addExtra(jg, "contact points", Joiner.on(", ").join(resourceReader.getProviderContactPoints(res)));
145
		addExtra(jg, "activity type", Joiner.on(", ").join(resourceReader.getActivityTypes(res)));
146
		// can't add multiple fields with same name, hence skipping
147
		addExtra(jg, "hosts", Joiner.on(", ").join(resourceReader.getHostedStuff(res)));
148
		addExtra(jg, "online access point", Joiner.on(", ").join(resourceReader.getAccessPoints(res)));
149
		//TODO: where to get it?
150
		addExtra(jg, "authorization", "");
151
		addExtra(jg, "protocol", Joiner.on(", ").join(resourceReader.getProtocols(res)));
152
		addExtra(jg,"curates", Joiner.on(", ").join(resourceReader.getCuratedObjects(res)));
153
		//TODO: where to get it?
154
		addExtra(jg, "runs on request", "");
155
		addExtra(jg, "delivers on request", Joiner.on(", ").join(resourceReader.getDeliversOnRequest(res)));
156
		addExtra(jg, "uses curation plan", Joiner.on(", ").join(resourceReader.getCurationPlans(res)));
157

    
158
		//for Projects
159
		addExtra(jg, "offers", Joiner.on(", ").join(resourceReader.getOfferedServiceUrls(res)));
160
		addExtra(jg, "started", Joiner.on(", ").join(resourceReader.getStartTimes(res)));
161

    
162
		jg.writeEndArray(); //end extras
163

    
164
		jg.writeEndObject();
165
		jg.close();
166
		return out.toString("UTF-8");
167
	}
168

    
169
	protected String getJsonForActor(final Resource res, final String resNameForCatalogue) throws IOException {
170
		JsonFactory jsonFactory = new JsonFactory();
171
		final ByteArrayOutputStream out = new ByteArrayOutputStream();
172
		BufferedOutputStream bos = new BufferedOutputStream(out);
173
		JsonGenerator jg = jsonFactory.createGenerator(bos, JsonEncoding.UTF8);
174
		jg.writeStartObject();
175
		writeCommonFields(jg, res, resNameForCatalogue);
176

    
177
		jg.writeArrayFieldStart("extras");
178
		addExtra(jg, "system:type", E39_Actor.getLocalName());
179
		//specific class
180
		addExtra(jg, "instance of", resourceReader.findSpecificType(res, E39_Actor).getLocalName());
181
		if (res.getURI().startsWith(PARTHENOS_BASE_URL))
182
			addExtra(jg, "Parthenos URL", res.getURI());
183
		addExtra(jg, "has member", Joiner.on(", ").join(resourceReader.getMemberUrls(res)));
184
		addExtra(jg, "is member of", Joiner.on(", ").join(resourceReader.isMemberOf(res)));
185
		addExtra(jg, "has contact point", Joiner.on(", ").join(resourceReader.getResourceDirectContactPoints(res)));
186
		addExtra(jg, "provides", Joiner.on(", ").join(resourceReader.getProvidedServiceUrls(res)));
187
		jg.writeEndArray();
188

    
189
		jg.writeEndObject();
190
		jg.close();
191
		return out.toString("UTF-8");
192
	}
193

    
194
	protected String getJsonForThing(final Resource res, final String resNameForCatalogue) throws IOException {
195
		JsonFactory jsonFactory = new JsonFactory();
196
		final ByteArrayOutputStream out = new ByteArrayOutputStream();
197
		BufferedOutputStream bos = new BufferedOutputStream(out);
198
		JsonGenerator jg = jsonFactory.createGenerator(bos, JsonEncoding.UTF8);
199
		jg.writeStartObject();
200
		writeCommonFields(jg, res, resNameForCatalogue);
201

    
202
		jg.writeArrayFieldStart("extras");
203
		addExtra(jg, "system:type", E70_Thing.getLocalName());
204
		//specific class
205
		addExtra(jg, "instance of", resourceReader.findSpecificType(res, E70_Thing).getLocalName());
206
		if (res.getURI().startsWith(PARTHENOS_BASE_URL)) {
207
			addExtra(jg, "Parthenos URL", res.getURI());
208
		}
209
		//TODO: things include digital objects, software, datasets, schema. Guess we should know what to add here.
210
		addExtra(jg, "is part of", Joiner.on(", ").join(resourceReader.getIsPartOfUrls(res)));
211
		addExtra(jg, "has part", Joiner.on(", ").join(resourceReader.getHasPartUrls(res)));
212
		addExtra(jg, "curated by", Joiner.on(", ").join(resourceReader.getCuratorUrls(res)));
213
		addExtra(jg, "curation plan", Joiner.on(", ").join(resourceReader.getCurationPlans(res)));
214
		addExtra(jg, "hosted by", Joiner.on(", ").join(resourceReader.getHostedBys(res)));
215
		//TODO where to get the encoding types? Should we through the Creation event?
216
		//addExtra(jg, "encoding type", Joiner.on(", ").join());
217
		//TODO where to get the schema/formats? Should we through the Creation event?
218
		//addExtra(jg, "encoding type", Joiner.on(", ").join());
219
		//TODO where to get the creator? Should we through the Creation event?
220
		//addExtra(jg, "creator", Joiner.on(", ").join());
221
		addExtra(jg, "subject", Joiner.on(", ").join(resourceReader.getSubjects(res)));
222
		addExtra(jg, "temporal coverage", Joiner.on(", ").join(resourceReader.getTemporalCoverages(res)));
223
		addExtra(jg, "spatial coverage", Joiner.on(", ").join(resourceReader.getSpatialCoverages(res)));
224

    
225

    
226
		jg.writeEndArray();
227

    
228
		jg.writeEndObject();
229
		jg.close();
230
		return out.toString("UTF-8");
231
	}
232

    
233
	protected void addExtra(final JsonGenerator jg, final String key, final String value) throws IOException {
234
		jg.writeStartObject();
235
		jg.writeStringField("key", key);
236
		jg.writeStringField("value", value);
237
		jg.writeEndObject();
238
	}
239

    
240
	protected void writeCommonFields(final JsonGenerator jg, final Resource res, final String resNameForCatalogue) throws IOException {
241
		//end of URI
242
		jg.writeStringField("name", resNameForCatalogue);
243
		//default license
244
		jg.writeStringField("license_id", "notspecified");
245
		String title = resourceReader.getTitle(res);
246
		if (StringUtils.isBlank(title))
247
			title = resNameForCatalogue;
248
		jg.writeStringField("title", title);
249
		//description
250
		jg.writeStringField("notes", resourceReader.getDescription(res));
251
		//the names of all superclasses of the entity
252
		jg.writeArrayFieldStart("tags");
253
		Iterator<String> classNames = resourceReader.getRDFClassNames(res);
254
		while (classNames.hasNext()) {
255
			jg.writeStartObject();
256
			jg.writeStringField("name", classNames.next());
257
			jg.writeEndObject();
258
		}
259
		jg.writeEndArray();
260
		//RI from which the entity has been collected, the source from which the RI collected the entity (if available).
261
		//TODO: other Actors to add as catalogue group?
262
		Iterator<String> providers = resourceReader.getProviderNames(res);
263
		jg.writeArrayFieldStart("groups");
264
		while(providers.hasNext()){
265
			String provider = providers.next();
266
			jg.writeStartObject();
267
			jg.writeStringField("name", provider);
268
			jg.writeEndObject();
269
		}
270
		jg.writeEndArray();
271
	}
272

    
273

    
274
	public ResourceReader getResourceReader() {
275
		return resourceReader;
276
	}
277

    
278
	public void setResourceReader(final ResourceReader resourceReader) {
279
		this.resourceReader = resourceReader;
280
	}
281

    
282
	public CatalogueAPIClient getCatalogueAPIClient() {
283
		return catalogueAPIClient;
284
	}
285

    
286
	public void setCatalogueAPIClient(final CatalogueAPIClient catalogueAPIClient) {
287
		this.catalogueAPIClient = catalogueAPIClient;
288
	}
289
}
(5-5/5)