1
|
/**
|
2
|
* Copyright (C) 2019 EDIT
|
3
|
* European Distributed Institute of Taxonomy
|
4
|
* http://www.e-taxonomy.eu
|
5
|
*
|
6
|
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
7
|
* See LICENSE.TXT at the top of this package for the full license terms.
|
8
|
*/
|
9
|
package eu.etaxonomy.cdm.io.descriptive.owl.in;
|
10
|
|
11
|
import java.util.Arrays;
|
12
|
import java.util.Collections;
|
13
|
import java.util.HashSet;
|
14
|
import java.util.List;
|
15
|
import java.util.Set;
|
16
|
import java.util.UUID;
|
17
|
|
18
|
import org.apache.logging.log4j.LogManager;
|
19
|
import org.apache.logging.log4j.Logger;
|
20
|
|
21
|
import com.hp.hpl.jena.rdf.model.Model;
|
22
|
import com.hp.hpl.jena.rdf.model.Resource;
|
23
|
import com.hp.hpl.jena.rdf.model.Statement;
|
24
|
|
25
|
import eu.etaxonomy.cdm.api.application.ICdmRepository;
|
26
|
import eu.etaxonomy.cdm.common.CdmUtils;
|
27
|
import eu.etaxonomy.cdm.common.URI;
|
28
|
import eu.etaxonomy.cdm.io.descriptive.owl.OwlUtil;
|
29
|
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
|
30
|
import eu.etaxonomy.cdm.model.common.Language;
|
31
|
import eu.etaxonomy.cdm.model.description.Character;
|
32
|
import eu.etaxonomy.cdm.model.description.Feature;
|
33
|
import eu.etaxonomy.cdm.model.description.MeasurementUnit;
|
34
|
import eu.etaxonomy.cdm.model.description.State;
|
35
|
import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
|
36
|
import eu.etaxonomy.cdm.model.media.Media;
|
37
|
import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
|
38
|
import eu.etaxonomy.cdm.model.reference.Reference;
|
39
|
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
|
40
|
import eu.etaxonomy.cdm.model.term.DefinedTerm;
|
41
|
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
|
42
|
import eu.etaxonomy.cdm.model.term.Representation;
|
43
|
import eu.etaxonomy.cdm.model.term.TermNode;
|
44
|
import eu.etaxonomy.cdm.model.term.TermType;
|
45
|
import eu.etaxonomy.cdm.model.term.TermVocabulary;
|
46
|
|
47
|
/**
|
48
|
* @author pplitzner
|
49
|
* @since May 26, 2019
|
50
|
*/
|
51
|
public class OwlImportUtil {
|
52
|
|
53
|
private final static Logger logger = LogManager.getLogger();
|
54
|
|
55
|
private static void addFeatureProperties(Feature feature, Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
56
|
if(termResource.hasProperty(OwlUtil.propFeatureIsCategorical)){
|
57
|
feature.setSupportsCategoricalData(termResource.getProperty(OwlUtil.propFeatureIsCategorical).getBoolean());
|
58
|
}
|
59
|
if(termResource.hasProperty(OwlUtil.propFeatureIsQuantitative)){
|
60
|
feature.setSupportsQuantitativeData(termResource.getProperty(OwlUtil.propFeatureIsQuantitative).getBoolean());
|
61
|
}
|
62
|
// import measurement units
|
63
|
Set<MeasurementUnit> measurementUnits = new HashSet<>();
|
64
|
List<Statement> measurementUnitStatements = termResource.listProperties(OwlUtil.propFeatureHasRecommendedMeasurementUnit).toList();
|
65
|
for (Statement statement : measurementUnitStatements) {
|
66
|
Resource measurementUnitResource = model.createResource(statement.getObject().toString());
|
67
|
MeasurementUnit measurementUnit = findTerm(MeasurementUnit.class, measurementUnitResource, repo, model, state);
|
68
|
if(measurementUnit==null){
|
69
|
measurementUnit = MeasurementUnit.NewInstance();
|
70
|
addTermProperties(measurementUnit, measurementUnitResource, repo, model, state);
|
71
|
}
|
72
|
measurementUnits.add(measurementUnit);
|
73
|
}
|
74
|
measurementUnits.forEach(unit->feature.addRecommendedMeasurementUnit(unit));
|
75
|
// import modifier TODO: create entire vocabulary if it cannot be found
|
76
|
Set<TermVocabulary<DefinedTerm>> modifierVocs = new HashSet<>();
|
77
|
List<Statement> modifierEnumStatements = termResource.listProperties(OwlUtil.propFeatureHasRecommendedModifierEnumeration).toList();
|
78
|
for (Statement statement : modifierEnumStatements) {
|
79
|
Resource modifierEnumResource = model.createResource(statement.getObject().toString());
|
80
|
TermVocabulary modifierVoc = findVocabulary(modifierEnumResource, repo, model, state);
|
81
|
if(modifierVoc!=null){
|
82
|
modifierVocs.add(modifierVoc);
|
83
|
}
|
84
|
}
|
85
|
modifierVocs.forEach(modiferVoc->feature.addRecommendedModifierEnumeration(modiferVoc));
|
86
|
// import statistical measures
|
87
|
Set<StatisticalMeasure> statisticalMeasures = new HashSet<>();
|
88
|
List<Statement> statisticalMeasureStatements = termResource.listProperties(OwlUtil.propFeatureHasRecommendedStatisticalMeasure).toList();
|
89
|
for (Statement statement : statisticalMeasureStatements) {
|
90
|
Resource statisticalMeasureResource = model.createResource(statement.getObject().toString());
|
91
|
StatisticalMeasure statisticalMeasure = findTerm(StatisticalMeasure.class, statisticalMeasureResource, repo, model, state);
|
92
|
if(statisticalMeasure==null){
|
93
|
statisticalMeasure = StatisticalMeasure.NewInstance();
|
94
|
addTermProperties(statisticalMeasure, statisticalMeasureResource, repo, model, state);
|
95
|
}
|
96
|
statisticalMeasures.add(statisticalMeasure);
|
97
|
}
|
98
|
statisticalMeasures.forEach(statisticalMeasure->feature.addRecommendedStatisticalMeasure(statisticalMeasure));
|
99
|
// import categorical enums TODO: create entire vocabulary if it cannot be found
|
100
|
Set<TermVocabulary<State>> stateVocs = new HashSet<>();
|
101
|
List<Statement> stateVocStatements = termResource.listProperties(OwlUtil.propFeatureHasSupportedCategoricalEnumeration).toList();
|
102
|
for (Statement statement : stateVocStatements) {
|
103
|
Resource stateVocResource = model.createResource(statement.getObject().toString());
|
104
|
TermVocabulary stateVoc = findVocabulary(stateVocResource, repo, model, state);
|
105
|
if(stateVoc!=null){
|
106
|
stateVocs.add(stateVoc);
|
107
|
}
|
108
|
}
|
109
|
stateVocs.forEach(stateVoc->feature.addSupportedCategoricalEnumeration(stateVoc));
|
110
|
}
|
111
|
|
112
|
static void addCharacterProperties(Character character, Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
113
|
addFeatureProperties(character, termResource, repo, model, state);
|
114
|
// import property
|
115
|
if(character.getProperty()!=null){
|
116
|
Statement propertyStatement = termResource.getProperty(OwlUtil.propCharacterHasProperty);
|
117
|
Resource propertyResource = model.createResource(propertyStatement.getObject().toString());
|
118
|
TermNode propertyNode = loadNode(propertyResource, repo, model, state);
|
119
|
if(propertyNode!=null){
|
120
|
character.setProperty(propertyNode);
|
121
|
}
|
122
|
else{
|
123
|
logger.error("Property not found for character: "+character);
|
124
|
return;
|
125
|
}
|
126
|
}
|
127
|
// import structure
|
128
|
if(character.getStructure()!=null){
|
129
|
Statement structureStatement = termResource.getProperty(OwlUtil.propCharacterHasStructure);
|
130
|
Resource structureResource = model.createResource(structureStatement.getObject().toString());
|
131
|
TermNode structureNode = loadNode(structureResource, repo, model, state);
|
132
|
if(structureNode!=null){
|
133
|
character.setStructure(structureNode);
|
134
|
}
|
135
|
else{
|
136
|
logger.error("Structure not found for character: "+character);
|
137
|
return;
|
138
|
}
|
139
|
}
|
140
|
// import structure modifier
|
141
|
if(character.getStructureModifier()!=null && termResource.hasProperty(OwlUtil.propCharacterHasStructureModfier)){
|
142
|
Statement structureModifierStatement = termResource.getProperty(OwlUtil.propCharacterHasStructureModfier);
|
143
|
Resource structureModifierResource = model.createResource(structureModifierStatement.getObject().toString());
|
144
|
DefinedTerm structureModifier = findTerm(DefinedTerm.class, structureModifierResource, repo, model, state);
|
145
|
character.setStructureModifier(structureModifier);
|
146
|
}
|
147
|
}
|
148
|
|
149
|
private static void addTermProperties(DefinedTermBase term, Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
150
|
term.setUuid(UUID.fromString(termResource.getProperty(OwlUtil.propUuid).getString()));
|
151
|
|
152
|
// term URI
|
153
|
String uriString = termResource.hasProperty(OwlUtil.propUri)?termResource.getProperty(OwlUtil.propUri).getString():null;
|
154
|
if(CdmUtils.isNotBlank(uriString)){
|
155
|
term.setUri(URI.create(uriString));
|
156
|
}
|
157
|
// symbol
|
158
|
String symbolString = termResource.hasProperty(OwlUtil.propTermSymbol)?termResource.getProperty(OwlUtil.propTermSymbol).getString():null;
|
159
|
if(CdmUtils.isNotBlank(symbolString)){
|
160
|
term.setSymbol(symbolString);
|
161
|
}
|
162
|
// symbol2
|
163
|
String symbol2String = termResource.hasProperty(OwlUtil.propTermSymbol2)?termResource.getProperty(OwlUtil.propTermSymbol2).getString():null;
|
164
|
if(CdmUtils.isNotBlank(symbol2String)){
|
165
|
term.setSymbol2(symbol2String);
|
166
|
}
|
167
|
// idInVocabulary
|
168
|
String idInVocabularyString = termResource.hasProperty(OwlUtil.propTermIdInVocabulary)?termResource.getProperty(OwlUtil.propTermIdInVocabulary).getString():null;
|
169
|
if(CdmUtils.isNotBlank(idInVocabularyString)){
|
170
|
term.setIdInVocabulary(idInVocabularyString);
|
171
|
}
|
172
|
|
173
|
// import representations
|
174
|
Set<Representation> representations = new HashSet<>();
|
175
|
termResource.listProperties(OwlUtil.propHasRepresentation).forEachRemaining(r->representations.add(OwlImportUtil.createRepresentation(repo, r, model)));
|
176
|
if(representations.isEmpty()){
|
177
|
logger.error("No representations found for term: "+termResource.getProperty(OwlUtil.propUuid));
|
178
|
}
|
179
|
representations.forEach(rep->term.addRepresentation(rep));
|
180
|
|
181
|
// import sources
|
182
|
Set<IdentifiableSource> sources = new HashSet<>();
|
183
|
termResource.listProperties(OwlUtil.propTermHasSource).forEachRemaining(sourceStatement->sources.add(OwlImportUtil.createSource(sourceStatement, repo, model)));
|
184
|
sources.forEach(source->term.addSource(source));
|
185
|
|
186
|
// add import source
|
187
|
IdentifiableSource importSource = IdentifiableSource.NewDataImportInstance(termResource.getURI());
|
188
|
importSource.setCitation(state.getConfig().getSourceReference());
|
189
|
term.addSource(importSource);
|
190
|
}
|
191
|
|
192
|
static <T extends DefinedTermBase> T findTerm(Class<T> clazz, Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
193
|
UUID termUuid = UUID.fromString(termResource.getProperty(OwlUtil.propUuid).getString());
|
194
|
List<T> terms = repo.getTermService().find(clazz, Collections.singleton(termUuid));
|
195
|
if(!terms.isEmpty()){
|
196
|
return terms.iterator().next();
|
197
|
}
|
198
|
return null;
|
199
|
}
|
200
|
|
201
|
private static TermVocabulary findVocabulary(Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
202
|
UUID termUuid = UUID.fromString(termResource.getProperty(OwlUtil.propUuid).getString());
|
203
|
return repo.getVocabularyService().find(termUuid);
|
204
|
}
|
205
|
|
206
|
private static TermNode loadNode(Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
207
|
UUID uuid = UUID.fromString(termResource.getProperty(OwlUtil.propUuid).getString());
|
208
|
return repo.getTermNodeService().load(uuid, Arrays.asList(new String[]{"term"}) );
|
209
|
}
|
210
|
|
211
|
private static Reference findReference(Resource resource, ICdmRepository repo){
|
212
|
UUID uuid = UUID.fromString(resource.getProperty(OwlUtil.propUuid).getString());
|
213
|
return repo.getReferenceService().find(uuid);
|
214
|
}
|
215
|
|
216
|
static Media findMedia(Resource resource, ICdmRepository repo){
|
217
|
UUID uuid = UUID.fromString(resource.getProperty(OwlUtil.propUuid).getString());
|
218
|
return repo.getMediaService().find(uuid);
|
219
|
}
|
220
|
|
221
|
static Feature createFeature(Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
222
|
Feature feature = findTerm(Feature.class, termResource, repo, model, state);
|
223
|
if(feature==null){
|
224
|
feature = Feature.NewInstance();
|
225
|
addFeatureProperties(feature, termResource, repo, model, state);
|
226
|
}
|
227
|
return feature;
|
228
|
}
|
229
|
|
230
|
static State createState(Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
231
|
State stateTerm = findTerm(State.class, termResource, repo, model, state);
|
232
|
if(stateTerm==null){
|
233
|
stateTerm = State.NewInstance();
|
234
|
}
|
235
|
return stateTerm;
|
236
|
}
|
237
|
|
238
|
private static Character createCharacter(Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
239
|
Character character = findTerm(Character.class, termResource, repo, model, state);
|
240
|
if(character==null){
|
241
|
character = Character.NewInstance();
|
242
|
}
|
243
|
return character;
|
244
|
}
|
245
|
|
246
|
static DefinedTermBase createTerm(Resource termResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
247
|
TermType termType = TermType.getByKey(termResource.getProperty(OwlUtil.propType).getString());
|
248
|
DefinedTermBase term = null;
|
249
|
// create new term
|
250
|
if(termType.equals(TermType.Feature)){
|
251
|
term = createFeature(termResource, repo, model, state);
|
252
|
}
|
253
|
else if(termType.equals(TermType.State)){
|
254
|
term = createState(termResource, repo, model, state);
|
255
|
}
|
256
|
else if(termType.equals(TermType.Character)){
|
257
|
term = createCharacter(termResource, repo, model, state);
|
258
|
}
|
259
|
else{
|
260
|
term = DefinedTerm.NewInstance(termType);
|
261
|
}
|
262
|
addTermProperties(term, termResource, repo, model, state);
|
263
|
return term;
|
264
|
}
|
265
|
|
266
|
static IdentifiableSource createSource(Statement sourceStatement, ICdmRepository repo, Model model) {
|
267
|
Resource sourceResource = model.createResource(sourceStatement.getObject().toString());
|
268
|
|
269
|
String typeString = sourceResource.getProperty(OwlUtil.propSourceType).getString();
|
270
|
IdentifiableSource source = IdentifiableSource.NewInstance(OriginalSourceType.getByKey(typeString));
|
271
|
|
272
|
if(sourceResource.hasProperty(OwlUtil.propSourceIdInSource)){
|
273
|
String idInSource = sourceResource.getProperty(OwlUtil.propSourceIdInSource).getString();
|
274
|
source.setIdInSource(idInSource);
|
275
|
}
|
276
|
|
277
|
// import citation
|
278
|
List<Statement> citationStatements = sourceResource.listProperties(OwlUtil.propSourceHasCitation).toList();
|
279
|
if(citationStatements.size()>1){
|
280
|
logger.error("More than one citations found for source. Choosing one arbitrarily. - "+sourceResource.toString());
|
281
|
}
|
282
|
if(!citationStatements.isEmpty()){
|
283
|
Statement citationStatement = citationStatements.iterator().next();
|
284
|
Resource citationResource = model.createResource(citationStatement.getObject().toString());
|
285
|
Reference reference = findReference(citationResource, repo);
|
286
|
if(reference==null){
|
287
|
reference = createReference(citationResource, model);
|
288
|
}
|
289
|
source.setCitation(reference);
|
290
|
}
|
291
|
return source;
|
292
|
}
|
293
|
|
294
|
static Reference createReference(Resource citationResource, Model model){
|
295
|
String titleString = citationResource.getProperty(OwlUtil.propReferenceTitle).getString();
|
296
|
Reference citation = ReferenceFactory.newGeneric();
|
297
|
// FIXME setting the UUID leads to org.hibernate.NonUniqueObjectException:
|
298
|
// A different object with the same identifier value was already associated with the session : [eu.etaxonomy.cdm.model.reference.Reference#12]
|
299
|
// citation.setUuid(UUID.fromString(citationResource.getProperty(OwlUtil.propUuid).getString()));
|
300
|
citation.setTitle(titleString);
|
301
|
return citation;
|
302
|
}
|
303
|
|
304
|
static TermVocabulary createVocabulary(Resource vocabularyResource, ICdmRepository repo, Model model, StructureTreeOwlImportState state){
|
305
|
TermType termType = TermType.getByKey(vocabularyResource.getProperty(OwlUtil.propType).getString());
|
306
|
// create new vocabulary
|
307
|
TermVocabulary vocabulary = TermVocabulary.NewInstance(termType);
|
308
|
vocabulary.setUuid(UUID.fromString(vocabularyResource.getProperty(OwlUtil.propUuid).getString()));
|
309
|
|
310
|
// voc URI
|
311
|
String vocUriString = vocabularyResource.hasProperty(OwlUtil.propUri)?vocabularyResource.getProperty(OwlUtil.propUri).getString():null;
|
312
|
if(CdmUtils.isNotBlank(vocUriString)){
|
313
|
vocabulary.setUri(URI.create(vocUriString));
|
314
|
}
|
315
|
|
316
|
// voc representations
|
317
|
Set<Representation> vocRepresentations = new HashSet<>();
|
318
|
vocabularyResource.listProperties(OwlUtil.propHasRepresentation).forEachRemaining(r->vocRepresentations.add(OwlImportUtil.createRepresentation(repo, r, model)));
|
319
|
if(vocRepresentations.isEmpty()){
|
320
|
logger.error("No representations found for vocabulary: "+vocabularyResource.getProperty(OwlUtil.propUuid));
|
321
|
}
|
322
|
vocRepresentations.forEach(rep->vocabulary.addRepresentation(rep));
|
323
|
|
324
|
IdentifiableSource importSource = IdentifiableSource.NewDataImportInstance(vocabularyResource.getURI());
|
325
|
importSource.setCitation(state.getConfig().getSourceReference());
|
326
|
vocabulary.addSource(importSource);
|
327
|
|
328
|
|
329
|
return vocabulary;
|
330
|
}
|
331
|
|
332
|
static Media createMedia(Resource mediaResource, StructureTreeOwlImportState state){
|
333
|
URI mediaUri = URI.create(mediaResource.getProperty(OwlUtil.propMediaUri).getString());
|
334
|
// create new media
|
335
|
Media media = Media.NewInstance(mediaUri, null, null, null);
|
336
|
media.setUuid(UUID.fromString(mediaResource.getProperty(OwlUtil.propUuid).getString()));
|
337
|
|
338
|
if(mediaResource.hasProperty(OwlUtil.propMediaTitle)){
|
339
|
// TODO: support multiple language titles
|
340
|
media.putTitle(Language.DEFAULT(), mediaResource.getProperty(OwlUtil.propMediaTitle).getString());
|
341
|
}
|
342
|
|
343
|
IdentifiableSource importSource = IdentifiableSource.NewDataImportInstance(mediaResource.getURI());
|
344
|
importSource.setCitation(state.getConfig().getSourceReference());
|
345
|
media.addSource(importSource);
|
346
|
|
347
|
return media;
|
348
|
}
|
349
|
|
350
|
static Representation createRepresentation(ICdmRepository repo, Statement repr, Model model) {
|
351
|
Resource repsentationResource = model.createResource(repr.getObject().toString());
|
352
|
|
353
|
String languageLabel = repsentationResource.getProperty(OwlUtil.propLanguage).getString();
|
354
|
UUID languageUuid = UUID.fromString(repsentationResource.getProperty(OwlUtil.propLanguageUuid).getString());
|
355
|
Language language = Language.getLanguageFromUuid(languageUuid);
|
356
|
if(language==null){
|
357
|
language = repo.getTermService().getLanguageByLabel(languageLabel);
|
358
|
}
|
359
|
if(language==null){
|
360
|
language = Language.getDefaultLanguage();
|
361
|
}
|
362
|
|
363
|
String abbreviatedLabel = repsentationResource.hasProperty(OwlUtil.propLabelAbbrev)?repsentationResource.getProperty(OwlUtil.propLabelAbbrev).getString():null;
|
364
|
String plural = repsentationResource.hasProperty(OwlUtil.propLabelPlural)?repsentationResource.getProperty(OwlUtil.propLabelPlural).getString():null;
|
365
|
String label = repsentationResource.getProperty(OwlUtil.propLabel).getString();
|
366
|
String description = repsentationResource.hasProperty(OwlUtil.propDescription)?repsentationResource.getProperty(OwlUtil.propDescription).getString():null;
|
367
|
Representation representation = Representation.NewInstance(description, label, abbreviatedLabel, language);
|
368
|
representation.setPlural(plural);
|
369
|
|
370
|
return representation;
|
371
|
}
|
372
|
|
373
|
}
|