Project

General

Profile

1
package eu.dnetlib.parthenos.registry;
2

    
3
import java.io.IOException;
4
import java.io.StringWriter;
5
import java.util.Map;
6
import java.util.Set;
7
import java.util.UUID;
8

    
9
import com.fasterxml.jackson.core.JsonFactory;
10
import com.fasterxml.jackson.core.JsonGenerator;
11
import com.google.common.collect.Maps;
12
import com.google.common.collect.Sets;
13
import eu.dnetlib.parthenos.CRM;
14
import eu.dnetlib.parthenos.CRMdig;
15
import eu.dnetlib.parthenos.CRMpe;
16
import eu.dnetlib.parthenos.publisher.ParthenosPublisherException;
17
import org.apache.commons.io.IOUtils;
18
import org.apache.commons.lang3.StringUtils;
19
import org.apache.commons.logging.Log;
20
import org.apache.commons.logging.LogFactory;
21
import org.apache.jena.assembler.AssemblerHelp;
22
import org.apache.jena.assembler.exceptions.AmbiguousSpecificTypeException;
23
import org.apache.jena.ontology.OntModel;
24
import org.apache.jena.ontology.OntModelSpec;
25
import org.apache.jena.rdf.model.*;
26
import org.apache.jena.vocabulary.RDF;
27
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
28
import org.gcube.informationsystem.resourceregistry.client.ResourceRegistryClient;
29
import org.gcube.informationsystem.resourceregistry.client.ResourceRegistryClientFactory;
30
import org.gcube.informationsystem.resourceregistry.publisher.ResourceRegistryPublisher;
31
import org.gcube.informationsystem.resourceregistry.publisher.ResourceRegistryPublisherFactory;
32
import org.springframework.beans.factory.annotation.Autowired;
33
import org.springframework.stereotype.Component;
34

    
35
/**
36
 * Created by Alessia Bardi on 26/09/2017.
37
 *
38
 * @author Alessia Bardi
39
 */
40
@Component
41
public class GCubeResourceRegistrator {
42

    
43
	private static final Log log = LogFactory.getLog(GCubeResourceRegistrator.class);
44

    
45
	private OntModel baseModel;
46

    
47
	@Autowired
48
	private FacetWriter facetWriter;
49
	@Autowired
50
	private RelWriter relWriter;
51

    
52
	private ResourceRegistryPublisher resourceRegistryPublisher;
53
	private ResourceRegistryClient resourceRegistryClient;
54

    
55
	public GCubeResourceRegistrator() {
56
		this.resourceRegistryPublisher = ResourceRegistryPublisherFactory.create();
57
		this.resourceRegistryClient = ResourceRegistryClientFactory.create();
58
		baseModel = ModelFactory.createOntologyModel(OntModelSpec.RDFS_MEM_TRANS_INF);
59
		baseModel.read(CRMpe.RDFS_URL);
60
		baseModel.read(CRM.RDFS_URL);
61
		baseModel.read(CRMdig.RDFS_URL);
62
	}
63

    
64
	public int unregister(final String datasourceApi){
65
		//TODO: implement me
66
		return -1;
67
	}
68

    
69
	/**
70
	 * Registers resources and relationships into the Parthenos Registry
71
	 *
72
	 * @param rdfRecord RDF record in RDF/XML PLAIN format
73
	 */
74
	public void register(final String rdfRecord, final String objIdentifier) throws IOException, ResourceRegistryException, ParthenosPublisherException {
75
		if (StringUtils.isBlank(rdfRecord)) {
76
			log.warn("Got empty record "+objIdentifier);
77
		} else {
78
			InfModel model = loadBaseModel();
79
			model.read(IOUtils.toInputStream(rdfRecord, "UTF-8"), CRMpe.NS);
80

    
81
			JsonFactory jsonFactory = new JsonFactory();
82
			Set<String> uriProcessed = Sets.newHashSet();
83
			/* Maps URI to ParthenosRegistryResource (with uuids) */
84
			Map<String, ParthenosRegistryResource> idMap = Maps.newHashMap();
85

    
86
			/* Resource */
87
			int registeredServices = processServices(model, uriProcessed, jsonFactory, idMap);
88
			int registeredDigitalObjects = processDigitalObjects(model, uriProcessed, jsonFactory, idMap);
89
			int registeredActors = processActors(model, uriProcessed, jsonFactory, idMap);
90
			int registeredProjects = processProjects(model, uriProcessed, jsonFactory, idMap);
91

    
92
			int total = registeredActors+registeredDigitalObjects+registeredProjects+registeredServices;
93
			log.debug(String.format("Registered %d resources from record with objIdentifier %s", total, objIdentifier));
94

    
95
			/* Relationships */
96
			int relTotal = 0;
97
			for(String uri : uriProcessed){
98
				relTotal += processRelationships(model, uri, idMap);
99
			}
100
			log.debug(String.format("Registered %d relationships from record with objIdentifier %s", relTotal, objIdentifier));
101
		}
102
	}
103

    
104
	private int processRelationships(final InfModel model, final String uri, final Map<String, ParthenosRegistryResource> idMap)
105
			throws IOException, ResourceRegistryException, ParthenosPublisherException {
106
		Resource subject = model.getResource(uri);
107
		String uuid = idMap.get(uri).getUuid();
108
		JsonFactory jsonFactory = new JsonFactory();
109
		int relCount = 0;
110

    
111
		if(subject.hasProperty(RDF.type, CRMpe.PE1_Service)){
112
			StmtIterator itOfferedBy = subject.listProperties(CRMpe.PP1i_is_currently_offered_by);
113
			while(itOfferedBy.hasNext()){
114
				Resource project = itOfferedBy.nextStatement().getResource();
115
				ParthenosRegistryResource source = idMap.get(uri);
116
				ParthenosRegistryResource projectRes = idMap.get(project.getURI());
117
				String relJson = relWriter.writeRelationship(jsonFactory, "PP1_currently_offers", projectRes.getUuid(), projectRes.getType(), source.getUuid(), source.getType());
118
				this.resourceRegistryPublisher.createIsRelatedTo("PP1_currently_offers", relJson);
119
				relCount++;
120
			}
121
			StmtIterator itProvidedBy = subject.listProperties(CRMpe.PP2_provided_by);
122
			while(itProvidedBy.hasNext()){
123
				Resource provider = itProvidedBy.nextStatement().getResource();
124
				ParthenosRegistryResource prr = idMap.get(uri);
125
				ParthenosRegistryResource providerRes = idMap.get(provider.getURI());
126
				String relJson = relWriter.writeRelationship(jsonFactory, "PP2_provided_by", prr.getUuid(), prr.getType(), providerRes.getUuid(), providerRes.getType());
127
				this.resourceRegistryPublisher.createIsRelatedTo("PP2_provided_by", relJson);
128
				relCount++;
129
				//TODO: IsRelatedTo the contact person of the provider. Interpret '"Follow path of service ‘Provided by’ and switch E39 for E21: E21- >p76->E51""
130
			}
131
			relCount += registerRelationship(CRMpe.PP45_has_competency, subject, idMap, jsonFactory);
132
			relCount += registerRelationship(CRMpe.PP4_hosts_object, subject, idMap, jsonFactory);
133
			relCount += registerRelationship(CRMpe.PP31_uses_curation_plan, subject, idMap, jsonFactory);
134
			relCount += registerRelationship(CRMpe.PP32_curates, subject, idMap, jsonFactory);
135
			relCount += registerRelationship(CRMpe.PP6_hosts_digital_object, subject, idMap, jsonFactory);
136
			relCount += registerRelationship(CRMpe.PP7_hosts_software_object, subject, idMap, jsonFactory);
137
			relCount += registerRelationship(CRMpe.PP8_hosts_dataset, subject, idMap, jsonFactory);
138
			relCount += registerRelationship(CRMpe.PP29_uses_access_protocol, subject, idMap, jsonFactory);
139
			relCount += registerRelationship(CRMpe.PP47_has_protocol_type, subject, idMap, jsonFactory);
140
			relCount += registerRelationship(CRMpe.PP48_uses_protocol_parameter, subject, idMap, jsonFactory);
141
			relCount += registerRelationship(CRMpe.PP46_brokers_access_to, subject, idMap, jsonFactory);
142
			relCount += registerRelationship(CRMpe.PP11_curates_volatile_digital_object, subject, idMap, jsonFactory);
143
			relCount += registerRelationship(CRMpe.PP12_curates_volatile_software, subject, idMap, jsonFactory);
144
			relCount += registerRelationship(CRMpe.PP13_curates_volatile_dataset, subject, idMap, jsonFactory);
145
			relCount += registerRelationship(CRMpe.PP15_delivers_on_request, subject, idMap, jsonFactory);
146
			relCount += registerRelationship(CRMpe.PP46_brokers_access_to, subject, idMap, jsonFactory);
147
		}
148
		if(subject.hasProperty(RDF.type, CRMpe.PE18_Dataset)){
149
			StmtIterator itPartOf = subject.listProperties(CRMpe.PP23i_is_dataset_part_of);
150
			while(itPartOf.hasNext()){
151
				Resource obj = itPartOf.nextStatement().getResource();
152
				ParthenosRegistryResource prr = idMap.get(uri);
153
				ParthenosRegistryResource objres = idMap.get(obj.getURI());
154
				String relJson = relWriter.writeRelationship(jsonFactory, "PP23_has_dataset_part", objres.getUuid(), objres.getType(), prr.getUuid(), prr.getType());
155
				this.resourceRegistryPublisher.createIsRelatedTo("PP23_has_dataset_part", relJson);
156
				relCount++;
157
			}
158
			//TODO: this is in the registry model but I am not sure what's going to happen...
159
			StmtIterator itIsAbout = subject.listProperties(CRM.P129_is_about);
160
			while(itIsAbout.hasNext()){
161
				Resource obj = itIsAbout.nextStatement().getResource();
162
				if(obj.hasProperty(RDF.type, CRM.E55_Type)) {
163
					ParthenosRegistryResource prr = idMap.get(uri);
164
					ParthenosRegistryResource objres = idMap.get(obj.getURI());
165
					String relJson = relWriter.writeRelationship(jsonFactory, "P129_is_about", prr.getUuid(), prr.getType(), objres.getUuid(), objres.getType());
166
					this.resourceRegistryPublisher.createIsRelatedTo("P129_is_about", relJson);
167
					relCount++;
168
				}
169
			}
170
		}
171
		if(subject.hasProperty(RDF.type, CRMpe.PE19_Persistent_Digital_Object)){
172
			relCount += registerRelationship(CRMpe.PP16_has_persistent_digital_object_part, subject, idMap, jsonFactory);
173
		}
174
		if(subject.hasProperty(RDF.type, CRMpe.PE20_Volatile_Digital_Object)){
175
			relCount += registerRelationship(CRMpe.PP17_has_snapshot, subject, idMap, jsonFactory);
176
			relCount += registerRelationship(CRMpe.PP18_has_digital_object_part, subject, idMap, jsonFactory);
177
		}
178
		if(subject.hasProperty(RDF.type, CRMpe.PE21_Persistent_Software)){
179
			relCount += registerRelationship(CRMpe.PP19_has_persistent_software_part, subject, idMap, jsonFactory);
180
		}
181
		if(subject.hasProperty(RDF.type, CRMpe.PE22_Persistent_Dataset)){
182
			relCount += registerRelationship(CRMpe.PP20_has_persistent_dataset_part, subject, idMap, jsonFactory);
183
			relCount += registerRelationship(CRMpe.PP39_is_metadata_for, subject, idMap, jsonFactory);
184
		}
185
		if(subject.hasProperty(RDF.type, CRMpe.PE23_Volatile_Software)){
186
			relCount += registerRelationship(CRMpe.PP21_has_software_part, subject, idMap, jsonFactory);
187
			relCount += registerRelationship(CRMpe.PP22_has_release, subject, idMap, jsonFactory);
188
		}
189
		if(subject.hasProperty(RDF.type, CRMpe.PE24_Volatile_Dataset)){
190
			relCount += registerRelationship(CRMpe.PP23_has_dataset_part, subject, idMap, jsonFactory);
191
			relCount += registerRelationship(CRMpe.PP24_has_dataset_snapshot, subject, idMap, jsonFactory);
192
			relCount += registerRelationship(CRMpe.PP41_is_index_of, subject, idMap, jsonFactory);
193
		}
194
		if(subject.hasProperty(RDF.type, CRMpe.PE26_RI_Project)){
195
			relCount += registerRelationship(CRMpe.PP25_has_maintaining_RI, subject, idMap, jsonFactory);
196
		}
197
		if(subject.hasProperty(RDF.type, CRMpe.PE35_Project)){
198
			relCount += registerRelationship(CRMpe.PP43_supported_project_activity,  subject, idMap, jsonFactory);
199
			relCount += registerRelationship(CRMpe.PP44_has_maintaining_team, subject, idMap, jsonFactory);
200
		}
201
		log.debug(String.format("Registered %d relationships for uri %s, uuid %s", relCount, uri, uuid));
202
		return relCount;
203
	}
204

    
205
	protected int registerRelationship(final Property rel, final Resource subject, final Map<String,ParthenosRegistryResource> idMap, final JsonFactory jsonFactory)
206
			throws IOException, ResourceRegistryException, ParthenosPublisherException {
207
		int relCount = 0;
208
		StmtIterator it = subject.listProperties(rel);
209
		while(it.hasNext()){
210
			Resource obj = it.nextStatement().getResource();
211
			if(obj == null) throw new ParthenosPublisherException(String.format("No target resource available for %s --> %s", subject.getURI(), rel.getURI()));
212
			ParthenosRegistryResource source = idMap.get(subject.getURI());
213
			ParthenosRegistryResource target = idMap.get(obj.getURI());
214
			String relJson = relWriter.writeRelationship(jsonFactory, rel.getLocalName(), source.getUuid(), source.getType(), target.getUuid(), target.getType());
215
			this.resourceRegistryPublisher.createIsRelatedTo(rel.getLocalName(), relJson);
216
			relCount++;
217
		}
218
		return relCount;
219
	}
220

    
221

    
222
	protected InfModel loadBaseModel() {
223
		return ModelFactory.createRDFSModel(baseModel);
224
	}
225

    
226
	protected int processServices(final InfModel model, final Set<String> uriProcessed, final JsonFactory jsonFactory, final Map<String, ParthenosRegistryResource> idMap)
227
			throws IOException, ResourceRegistryException {
228
		log.debug("Processing services");
229
		int count = 0;
230
		int total = 0;
231
		ResIterator iter = model.listResourcesWithProperty(RDF.type, CRMpe.PE1_Service);
232
		while (iter.hasNext()) {
233
			total++;
234
			Resource res = iter.nextResource();
235
			String resourceURI = res.getURI();
236
			if (!uriProcessed.contains(resourceURI)) {
237
				ParthenosRegistryResource prr = processService(res, jsonFactory, idMap);
238
				this.resourceRegistryPublisher.createResource(prr.getType(), prr.getJson());
239
				uriProcessed.add(resourceURI);
240
				idMap.put(resourceURI, prr);
241
				count++;
242
			} else {
243
				log.debug(resourceURI + " already processed, now skipping it");
244
			}
245
		}
246
		log.debug(String.format("Registered %d/%d services", count, total));
247
		return count;
248

    
249
	}
250

    
251
	private ParthenosRegistryResource processService(final Resource res, final JsonFactory jsonFactory, final Map<String, ParthenosRegistryResource> idMap) throws IOException {
252
		log.debug("Processing " + res.getURI());
253

    
254
		StringWriter sw = new StringWriter();
255
		JsonGenerator jg = jsonFactory.createGenerator(sw);
256
		jg.writeStartObject();
257
		String specificType = findSpecificType(res, CRMpe.PE1_Service).getLocalName();
258
		String uuid = writeCommon(res, specificType, jg, idMap);
259
		//******THE FACETS *******//
260
		jg.writeArrayFieldStart("consistsOf");
261
		//list of facets
262
		writeCommonFacets(res, jg);
263
		facetWriter.writeEventFacet(jg);
264
		facetWriter.writeRightsFacet(jg, res);
265
		if (res.hasProperty(CRMpe.PP2_provided_by)) {
266
			//TODO: shouldn't this be a rel to an actor?
267
			Resource provider = res.getPropertyResourceValue(CRMpe.PP2_provided_by);
268
			facetWriter.writeContactReferenceFacet(jg, provider);
269
		}
270
		facetWriter.writeDesignatedAccessPointFacet(jg, res);
271
		jg.writeEndArray();
272
		jg.writeEndObject();
273
		jg.close();
274
		String json = sw.toString();
275
		log.debug(json);
276
		return new ParthenosRegistryResource().setJson(json).setType(specificType).setUuid(uuid);
277
	}
278

    
279
	/**
280
	 * Write the common properties: header, class for all resources
281
	 *
282
	 * @param resource  input Resource.
283
	 * @param className name of the class for the registry
284
	 * @param jg        JsonGenerator to write with.
285
	 * @param idMap     map of the already assigned UUID
286
	 * @return the uuid of the resource
287
	 */
288
	protected String writeCommon(final Resource resource, final String className, final JsonGenerator jg, final Map<String, ParthenosRegistryResource> idMap) throws IOException {
289
		String uuid;
290
		if (idMap.containsKey(resource.getURI())) {
291
			uuid = idMap.get(resource.getURI()).getUuid();
292
		} else {
293
			uuid = UUID.randomUUID().toString();
294
			idMap.put(resource.getURI(), new ParthenosRegistryResource().setUuid(uuid));
295
		}
296
		jg.writeStartObject();
297
		jg.writeObjectFieldStart("header");
298
		jg.writeStringField("uuid", uuid);
299
		jg.writeEndObject();
300
		jg.writeStringField("@class", className);
301
		return uuid;
302
	}
303

    
304
	/**
305
	 * Write the common facets: identifier and info facets
306
	 *
307
	 * @param res
308
	 * @param jg
309
	 */
310
	protected void writeCommonFacets(final Resource res, final JsonGenerator jg) throws IOException {
311
		facetWriter.writeIdentifierFacet(jg, res.getURI());
312
		facetWriter.writeP1Facets(jg, res);
313
		facetWriter.writeInfoFacet(jg, res);
314
	}
315

    
316
	protected int processDigitalObjects(final InfModel model, final Set<String> uriProcessed, final JsonFactory jsonFactory, final Map<String, ParthenosRegistryResource> idMap)
317
			throws IOException, ResourceRegistryException {
318
		log.debug("Processing digital objects (include dataset and software)");
319
		int count = 0;
320
		int total = 0;
321
		ResIterator iterDo = model.listResourcesWithProperty(RDF.type, CRMdig.D1_Digital_Object);
322
		while (iterDo.hasNext()) {
323
			total++;
324
			Resource res = iterDo.nextResource();
325
			String resourceURI = res.getURI();
326
			if (!uriProcessed.contains(resourceURI)) {
327
				ParthenosRegistryResource prr = processDigitalObject(res, jsonFactory, idMap);
328
				this.resourceRegistryPublisher.createResource(prr.getType(), prr.getJson());
329
				uriProcessed.add(resourceURI);
330
				idMap.put(resourceURI, prr);
331
				count++;
332
			} else {
333
				log.debug(resourceURI + " already processed, now skipping it");
334
			}
335
		}
336
		log.debug(String.format("Registered %d/%d digital objects", count, total));
337
		return count;
338
	}
339

    
340
	protected ParthenosRegistryResource processDigitalObject(final Resource res, final JsonFactory jsonFactory, final Map<String, ParthenosRegistryResource> idMap)
341
			throws IOException {
342
		log.debug("Processing " + res.getURI());
343
		String specificType = findSpecificType(res, CRMdig.D1_Digital_Object).getLocalName();
344
		StringWriter sw = new StringWriter();
345
		JsonGenerator jg = jsonFactory.createGenerator(sw);
346
		jg.writeStartObject();
347

    
348
		String uuid = writeCommon(res, specificType, jg, idMap);
349
		//******THE FACETS *******//
350
		jg.writeArrayFieldStart("consistsOf");
351
		//list of facets
352
		writeCommonFacets(res, jg);
353
		facetWriter.writeTemporalCoverageFacet(jg, res);
354
		facetWriter.writeRightsFacet(jg, res);
355

    
356
		jg.writeEndArray();
357
		jg.writeEndObject();
358
		jg.close();
359
		String json = sw.toString();
360
		log.debug(json);
361
		return new ParthenosRegistryResource().setUuid(uuid).setType(specificType).setJson(json);
362
	}
363

    
364
	protected int processActors(final InfModel model, Set<String> uriProcessed, final JsonFactory jsonFactory, final Map<String, ParthenosRegistryResource> idMap)
365
			throws IOException {
366
		log.debug("Processing actors");
367
		int count = 0;
368
		int total = 0;
369
		ResIterator iterActors = model.listResourcesWithProperty(RDF.type, CRM.E39_Actor);
370
		while (iterActors.hasNext()) {
371
			total++;
372
			Resource res = iterActors.nextResource();
373
			String resourceURI = res.getURI();
374
			if (!uriProcessed.contains(resourceURI)) {
375
				ParthenosRegistryResource prr = processActor(res, jsonFactory, idMap);
376
				uriProcessed.add(resourceURI);
377
				idMap.put(resourceURI, prr);
378
				count++;
379

    
380
			} else {
381
				log.debug(resourceURI + " already processed, now skipping it");
382
			}
383
		}
384
		log.debug(String.format("Registered %d/%d actors", count, total));
385
		return count;
386
	}
387

    
388
	protected ParthenosRegistryResource processActor(final Resource r, final JsonFactory jsonFactory, final Map<String, ParthenosRegistryResource> idMap) throws IOException {
389
		log.debug("Processing " + r.getURI());
390
		String specificType = findSpecificType(r, CRM.E39_Actor).getLocalName();
391
		StringWriter sw = new StringWriter();
392
		JsonGenerator jg = jsonFactory.createGenerator(sw);
393
		jg.writeStartObject();
394

    
395
		String uuid = writeCommon(r, specificType, jg, idMap);
396
		//******THE FACETS *******//
397
		jg.writeArrayFieldStart("consistsOf");
398
		//list of facets
399
		writeCommonFacets(r, jg);
400
		facetWriter.writeContactReferenceFacet(jg, r);
401

    
402
		jg.writeEndArray();
403
		jg.writeEndObject();
404
		jg.close();
405
		String json = sw.toString();
406
		log.debug(json);
407
		return new ParthenosRegistryResource().setJson(json).setType(specificType).setUuid(uuid);
408
	}
409

    
410
	protected int processProjects(final InfModel model, Set<String> uriProcessed, final JsonFactory jsonFactory, final Map<String, ParthenosRegistryResource> idMap)
411
			throws IOException, ResourceRegistryException {
412
		log.debug("Processing projects");
413
		int count = 0;
414
		int total = 0;
415
		ResIterator iterProjects = model.listResourcesWithProperty(RDF.type, CRMpe.PE35_Project);
416
		while (iterProjects.hasNext()) {
417
			total++;
418
			Resource res = iterProjects.nextResource();
419
			String resourceURI = res.getURI();
420
			if (!uriProcessed.contains(resourceURI)) {
421
				ParthenosRegistryResource prr = processProject(res, jsonFactory, idMap);
422
				this.resourceRegistryPublisher.createResource(prr.getType(), prr.getJson());
423
				uriProcessed.add(resourceURI);
424
				idMap.put(resourceURI, prr);
425
				count++;
426
			} else {
427
				log.debug(resourceURI + " already processed, now skipping it");
428
			}
429
		}
430
		log.debug(String.format("Registered %d/%d projects", count, total));
431
		return count;
432
	}
433

    
434
	protected ParthenosRegistryResource processProject(final Resource res, final JsonFactory jsonFactory, final Map<String, ParthenosRegistryResource> idMap) throws IOException {
435
		log.debug("Processing " + res.getURI());
436
		String specificType = findSpecificType(res, CRMpe.PE35_Project).getLocalName();
437
		StringWriter sw = new StringWriter();
438
		JsonGenerator jg = jsonFactory.createGenerator(sw);
439
		jg.writeStartObject();
440

    
441
		String uuid = writeCommon(res, specificType, jg, idMap);
442
		jg.writeArrayFieldStart("consistsOf");
443
		writeCommonFacets(res, jg);
444

    
445
		jg.writeEndArray();
446
		jg.writeEndObject();
447
		jg.close();
448
		String json = sw.toString();
449
		log.debug(json);
450
		return new ParthenosRegistryResource().setJson(json).setType(specificType).setUuid(uuid);
451
	}
452

    
453
	/**
454
	 * Finds the most specific type of res.
455
	 *
456
	 * @param res          Resource you want to find the most specific type
457
	 * @param fallbackType Resource representing the type to return if there is no type or if we get AmbiguousSpecificTypeException
458
	 * @return Resource: the most specific type, if any. fallbackType otherwise
459
	 */
460
	protected Resource findSpecificType(final Resource res, final Resource fallbackType) {
461
		Resource specType = fallbackType;
462
		try {
463
			specType = AssemblerHelp.findSpecificType(res, fallbackType);
464
		} catch (AmbiguousSpecificTypeException e) {
465
			log.warn(res.getURI() + ": " + e.getMessage());
466
		}
467
		return specType;
468
	}
469

    
470
	public FacetWriter getFacetWriter() {
471
		return facetWriter;
472
	}
473

    
474
	public void setFacetWriter(final FacetWriter facetWriter) {
475
		this.facetWriter = facetWriter;
476
	}
477
}
(2-2/6)