Commit d28c5959 authored by Richard Bruskiewich's avatar Richard Bruskiewich Committed by Matija Obreza
Browse files

Substantially complete RDF dumping of Trait ("Parameter"),

ParameterCategory and Method (w/ Scale) meta-data.  Considerable
progress on Crop RDF dump (to complete manana).
parent 6f38836f
......@@ -17,7 +17,10 @@
package org.genesys2.server.model.genesys;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import javax.persistence.Column;
......@@ -91,11 +94,7 @@ public class Method extends GlobalVersionedAuditedModel implements AclAwareModel
return this.method;
}
public String getMethod(Locale locale) {
return getMethodLocal(locale);
}
private synchronized String getMethodLocal(Locale locale) {
private synchronized void parseMethodLocal() {
if (this.methodJ == null && this.i18n != null) {
ObjectMapper mapper = new ObjectMapper();
try {
......@@ -104,6 +103,38 @@ public class Method extends GlobalVersionedAuditedModel implements AclAwareModel
e.printStackTrace();
}
}
}
@Transient
private Map<String,String> methodMap = new HashMap<String,String>();
/**
* Method to return the map of available languages keys
* @return Map<String,String> with language code as the key and the vernacular string as the value.
*/
public Map<String,String> getLocalMethodMap() {
return buildLocalMethodMap() ;
}
private synchronized Map<String,String> buildLocalMethodMap() {
if (this.methodMap.isEmpty() && this.i18n != null) {
parseMethodLocal() ;
Iterator<String> languages = this.methodJ.fieldNames() ;
while(languages.hasNext()) {
String language = languages.next() ;
methodMap.put(language, this.methodJ.get(language).textValue()) ;
}
}
return methodMap ;
}
public String getMethod(Locale locale) {
return getMethodLocal(locale);
}
private synchronized String getMethodLocal(Locale locale) {
parseMethodLocal() ;
return this.methodJ != null && this.methodJ.has(locale.getLanguage()) ? this.methodJ.get(locale.getLanguage()).textValue() : this.method;
}
......
......@@ -30,6 +30,8 @@ public interface CropService {
Crop getCrop(String shortName);
List<Crop> listCrops();
List<Crop> list(Locale locale);
List<Crop> getCrops(Taxonomy taxonomy);
......
......@@ -34,10 +34,10 @@ public interface TraitService {
Page<Parameter> listTraits(Crop crop, Pageable pageable);
Parameter getTrait(long traitId);
List<Parameter> listTraits();
Parameter getTrait(long traitId);
List<Method> getTraitMethods(Parameter trait);
Method getMethod(long traitId);
......@@ -46,6 +46,8 @@ public interface TraitService {
Page<Method> listMethods(Pageable pageable);
List<Method> listMethods();
/**
* Add new crop descriptor Property Category
*
......
......@@ -69,6 +69,12 @@ public class CropServiceImpl implements CropService {
return cropRepository.findByShortName(shortName);
}
@Override
public List<Crop> listCrops() {
return cropRepository.findAll();
}
@Override
public List<Crop> list(final Locale locale) {
List<Crop> crops = cropRepository.findAll();
......@@ -275,4 +281,5 @@ public class CropServiceImpl implements CropService {
public List<CropRule> getCropRules(Crop crop) {
return crop == null ? null : cropRuleRepository.findByCrop(crop);
}
}
......@@ -410,6 +410,7 @@ public class GenesysServiceImpl implements GenesysService, TraitService, Dataset
public List<Parameter> listTraits() {
return parameterRepository.findAll(new Sort(new Order(Direction.ASC, "id")));
}
@Override
public Page<Parameter> listTraits(Pageable pageable) {
return parameterRepository.findAll(pageable);
......@@ -435,6 +436,11 @@ public class GenesysServiceImpl implements GenesysService, TraitService, Dataset
return methodRepository.findOne(methodId);
}
@Override
public List<Method> listMethods() {
return methodRepository.findAll(new Sort(new Order(Direction.ASC, "id")));
}
@Override
public Page<Method> listMethods(Pageable pageable) {
return methodRepository.findAll(pageable);
......
/**
* Copyright 2014 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package org.genesys2.server.servlet.controller.rdf;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDFS;
import org.genesys2.server.model.impl.Crop;
import org.genesys2.server.service.CropService;
import org.genesys2.spring.ResourceNotFoundException;
import org.bioversityinternational.model.germplasm.CCO;
import org.bioversityinternational.model.rdf.dwc.DarwinCore;
@Controller
@RequestMapping(value = "/crops", method = RequestMethod.GET, headers = "accept=text/turtle", produces = RdfBaseController.RDF_MEDIATYPE_TURTLE)
public class CropControllerRdf extends RdfBaseController {
@Autowired
private CropService cropService;
/*
* Method generates RDF for one crop record as RDF.
*
* Crop RDF exemplar:
*
cco:MusaTaxon a dwc:Taxon, skos:Collection;
dwc:scientificName "Musa" ;
dwc:vernacularName "Musa"@en ;
dwc:vernacularName "Musa"@es ;
dwc:vernacularName "Муса"@ru ;
dwc:vernacularName "穆萨" @zh ;
dc:description "Bananas and plantains"@en ;
dc:description "Los bananos y plátanos"@es ;
dc:description "Бананы и бананы"@ru ;
dc:description "香蕉和大蕉"@zh ;
dc:hasVersion "Revision: 0.1" ;
dc:creator "Bioversity International" ;
skos:member cco:MusaAcuminata, cco:MusaBalbisiana
.
cco:MusaAcuminata a cco:Species;
dwc:scientificName "Musa acuminata" ;
dwc:genus "Musa" ;
dc:description "Wild progenitor of domesticated bananas."@en ;
dc:description "Progenitor salvaje de plátanos domesticados."@es ;
dc:description "Дикий прародителем домашних бананов."@ru ;
dc:description "香蕉驯化野生祖。"@zh ;
cco:speciesIncluded "true"
.
*/
private void wrapCrop(Model model, Crop crop) {
Resource subject = createSubject(model, crop, CCO.getURI(), crop.getShortName()+" Taxon") ;
subject.addProperty(DarwinCore.scientificName, crop.getShortName()) ;
String seeAlso = crop.getRdfUri() ;
if(seeAlso!=null)
subject.addProperty(
RDFS.seeAlso,
model.createResource(seeAlso)
) ;
/*
* vernacular names & descriptions in i18n
*
Map<String,String> vernacularNameMap = trait.getLocalNameMap() ;
for( String language : vernacularNameMap.keySet() ) {
Literal vernacularNameLiteral =
model.createLiteral(vernacularNameMap.get(language), language) ;
traitSubject.addLiteral(DarwinCore.vernacularName,vernacularNameLiteral) ;
}
Map<String,String> vernacularDefinitionMap = trait.getLocalDefinitionMap() ;
for( String language : vernacularDefinitionMap.keySet() ) {
Literal vernacularDefinitionLiteral =
model.createLiteral(vernacularDefinitionMap.get(language), language) ;
traitSubject.addLiteral(DC.description,vernacularDefinitionLiteral) ;
}
*/
/*
model.addAttribute("cropTaxonomies", cropService.getCropTaxonomies(crop, new PageRequest(0, 20, new Sort("taxonomy.genus", "taxonomy.species"))));
*/
}
@RequestMapping
public @ResponseBody
String dumpCrops() {
Model model = startModel() ;
List<Crop> crops = cropService.listCrops() ;
for(Crop crop : crops) wrapCrop( model, crop) ;
return endModel(model) ;
}
@RequestMapping("/{shortName}")
public @ResponseBody
String dumpCrop(@PathVariable(value = "shortName") String shortName) {
_logger.debug("Dump RDF data for crop: " + shortName);
Model model = startModel() ;
Crop crop = cropService.getCrop(shortName);
if (crop == null) {
throw new ResourceNotFoundException();
}
wrapCrop(model,crop) ;
return endModel(model) ;
}
}
......@@ -19,9 +19,18 @@ package org.genesys2.server.servlet.controller.rdf;
import java.util.List;
import java.util.Map;
import org.bioversityinternational.model.germplasm.CCO;
import org.bioversityinternational.model.rdf.skos.SKOS;
import org.genesys2.server.model.genesys.Metadata;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDFS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.genesys2.server.model.genesys.Method;
import org.genesys2.server.model.genesys.Parameter;
import org.genesys2.server.model.genesys.ParameterCategory;
......@@ -29,17 +38,10 @@ import org.genesys2.server.model.genesys.TraitCode;
import org.genesys2.server.model.impl.Crop;
import org.genesys2.server.service.TraitService;
import org.genesys2.spring.ResourceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
//import org.genesys2.server.model.genesys.Metadata; // not yet integrated...
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDFS;
import org.bioversityinternational.model.germplasm.CCO;
import org.bioversityinternational.model.rdf.skos.SKOS;
/**
* Controller which simply handles RDF Turtle meta-data requests
......@@ -162,7 +164,6 @@ public class DescriptorControllerRdf extends RdfBaseController {
Resource categorySubject = categorySubject(model, category) ;
traitSubject.addProperty(CCO.category, categorySubject) ;
//model.addAttribute("traitMethods", traitService.getTraitMethods(trait));
Map<String,String> vernacularTitleMap = trait.getLocalTitleMap() ;
for( String language : vernacularTitleMap.keySet() ) {
......@@ -189,7 +190,7 @@ public class DescriptorControllerRdf extends RdfBaseController {
* Method to retrieve list of all trait properties in the database, formatted as Turtle RDF
* @return List of RDF Turtle formatted trait properties
*/
@RequestMapping()
@RequestMapping("/traits")
public @ResponseBody
Object dumpTraits() {
......@@ -310,9 +311,10 @@ public class DescriptorControllerRdf extends RdfBaseController {
* Creates and annotates a Method subject
*/
private Resource[] traitAndMethodSubjects(Model model, Parameter trait, Method method) {
Resource[] subjects = new Resource[2] ;
Resource[] subjects = new Resource[3] ;
subjects[0] = traitSubject(model, trait) ;
subjects[1] = createProperty(model, method, METHOD_NS, trait.getTitle()+" Method" ) ;
subjects[2] = createProperty(model, method, SCALE_NS, trait.getTitle()+" Scale" ) ;
return subjects ;
}
......@@ -324,6 +326,7 @@ public class DescriptorControllerRdf extends RdfBaseController {
Resource[] subjects = traitAndMethodSubjects(model,trait,method) ;
Resource traitSubj = subjects[0] ;
Resource methodSubj = subjects[1] ;
Resource scaleSubj = subjects[2] ;
String seeAlso = method.getRdfUri() ;
if(seeAlso!=null)
......@@ -339,16 +342,8 @@ public class DescriptorControllerRdf extends RdfBaseController {
methodSubj.addProperty( CCO.trait, traitSubj ) ;
/*
//model.addAttribute("traitMethods", traitService.getTraitMethods(trait));
Map<String,String> vernacularTitleMap = trait.getLocalTitleMap() ;
for( String language : vernacularTitleMap.keySet() ) {
Literal vernacularNameLiteral =
model.createLiteral(vernacularTitleMap.get(language), language) ;
methodSubject.addLiteral(SKOS.prefLabel,vernacularNameLiteral) ;
}
TODO - The Parameter table doesn't yet appear to track trait descriptions...
TODO - The Parameter table doesn't yet appear to track method names...
Map<String,String> vernacularTitleMap = trait.getLocalTitleMap() ;
......@@ -357,17 +352,141 @@ public class DescriptorControllerRdf extends RdfBaseController {
model.createLiteral(vernacularTitleMap.get(language), language) ;
subject.addLiteral(SKOS.prefLabel,vernacularNameLiteral) ;
}
*/
// Method "definitions" are in the "method" field...in the vernacular
Map<String,String> vernacularMethodMap = method.getLocalMethodMap() ;
if(!(vernacularMethodMap==null || vernacularMethodMap.isEmpty()))
for( String language : vernacularMethodMap.keySet() ) {
String vernacularMethod = vernacularMethodMap.get(language) ;
if(vernacularMethod==null) continue;
Literal vernacularNameLiteral =
model.createLiteral(vernacularMethod, language) ;
methodSubj.addLiteral(SKOS.prefLabel,vernacularNameLiteral) ;
}
/*
List<Metadata> metadata = traitService.listMetadataByMethod(method);
*/
Resource scaleVocabulary = CCO.Vocabulary.set(model, scaleSubj, CCO.Vocabulary.SCALE, crop.getShortName()) ;
scaleSubj.addProperty( SKOS.related, methodSubj ) ;
scaleSubj.addProperty( CCO.method, methodSubj ) ;
String units = method.getUnit() ;
// Options associated with scale...
if (method.isCoded()) {
Map<String, String> codeMap = TraitCode.parseCodeMap(method.getOptions());
//model.addAttribute("codeMap", codeMap);
wrapScaleValues( model, trait, method, scaleSubj, scaleVocabulary, units) ;
// Not sure what to do with Method statistics for now...
//model.addAttribute("codeStatistics", traitService.getMethodStatistics(method));
} else {
if(!(units == null || units.isEmpty())) {
scaleSubj.addProperty( CCO.scaleUnit, units ) ;
}
}
*/
}
/* RDF of a Nominal Scale associated with a given method
cco:fruitLengthScale a skos:Concept;
skos:broader cco:MusaTraitScale ;
skos:related cco:fruitLengthMethod, cco:fruitLengthMethod2 ;
cco:method cco:fruitLengthMethod, cco:fruitLengthMethod2 ;
skos:prefLabel "Fruit length scale"@en;
skos:prefLabel "Escala Longitud de los frutos [cm] "@es;
dcterms:created "2014/01/14 12:00:00";
dcterms:modified "2014/01/14 12:00:00";
skos:inScheme cco:MusaTraitScaleVocabulary ;
skos:definition "1 =<15 cm, 2 16- 20 cm, 3 21- 25 cm, 4 26- 30 cm, 5 >=31 cm"@en;
skos:definition "1 =< 15 cm, 2 16-20 cm, 3 21-25 cm, 4 26-30 cm, 5 > =31 cm"@es;
cco:scaleType "Nominal";
cco:scaleUnit cco:fruitLengthScaleValues
.
cco:fruitLengthScaleValues a skos:Collection;
skos:prefLabel "Fruit length scale values"@en ;
skos:prefLabel "Valores para Longitud de los frutos [cm]"@es ;
dcterms:created "2014/01/14 12:00:00";
dcterms:modified "2014/01/14 12:00:00";
skos:definition "Controlled list of values for Fruit length"@en;
skos:definition "Lista controlada de valores para Longitud de los frutos [cm]"@es;
skos:member cco:fruitLengthScaleValue1, cco:fruitLengthScaleValue2, cco:fruitLengthScaleValue3, cco:fruitLengthScaleValue4, cco:fruitLengthScaleValue5
.
cco:fruitLengthScaleValue1
a cco:IntegerValueRange ;
cco:integerMinValue "0"^^xsd:integer ;
cco:integerMaxValue "15"^^xsd:integer ;
cco:scaleUnit "cm" ;
skos:broader cco:fruitLengthScale;
dcterms:created "2014/01/14 12:00:00";
dcterms:modified "2014/01/14 12:00:00";
skos:prefLabel "=<15 cm"@en ;
skos:prefLabel "=<15 cm"@es ;
skos:altLabel "1" ;
skos:definition "=<15 cm"@en ;
skos:definition "=<15 cm"@es ;
skos:inScheme cco:MusaTraitScaleVocabulary
.
*/
private void wrapScaleValues(
Model model, Parameter trait, Method method,
Resource scaleSubj, Resource scaleVocabulary, String units
) {
Resource scaleValuesSubj = createProperty(model, method, SCALE_NS, trait.getTitle()+" Scale Values", true) ;
scaleSubj.addProperty( CCO.scaleType, "Nominal" ) ;
scaleSubj.addProperty( CCO.scaleUnit, scaleValuesSubj ) ;
scaleValuesSubj.addProperty(SKOS.inScheme, scaleVocabulary ) ;
// Enumerate da Options....
String options = method.getOptions() ;
scaleSubj.addProperty( SKOS.definition, options ) ;
Map<String, String> codeMap = TraitCode.parseCodeMap(options);
int n = 1 ;
for(String code : codeMap.keySet()) {
Resource valueSubj = createProperty(model, method, SCALE_NS, trait.getTitle()+" Scale Value"+n) ;
scaleValuesSubj.addProperty( SKOS.member, valueSubj ) ;
valueSubj.addProperty( SKOS.broader, scaleSubj ) ;
valueSubj.addProperty(SKOS.inScheme, scaleVocabulary ) ;
valueSubj.addProperty( SKOS.altLabel, code ) ;
// TODO: do I need to use skos:definition and
// have vernacular options? Nah! Overkill for now!
valueSubj.addProperty( SKOS.prefLabel, codeMap.get(code) ) ;
if(!(units == null || units.isEmpty())) {
valueSubj.addProperty( CCO.scaleUnit, units ) ;
}
n += 1 ;
}
}
/**
* Method to retrieve list of all trait properties in the database, formatted as Turtle RDF
* @return List of RDF Turtle formatted trait properties
*/
@RequestMapping("/methods")
public @ResponseBody
Object dumpMethods() {
Model model = startModel() ;
for(Method method : traitService.listMethods()) {
Parameter trait = method.getParameter() ;
wrapMethod(model, trait, method) ;
}
return endModel(model) ;
}
/**
* Method to publish a single crop trait method and associated scale meta-data, as multi-lingual RDF
......@@ -393,13 +512,15 @@ public class DescriptorControllerRdf extends RdfBaseController {
if (!method.getParameter().getId().equals(trait.getId())) {
_logger.warn("Method does not belong to Param");
throw new ResourceNotFoundException();
}
Model model = startModel() ;
wrapTrait(model, trait) ;
wrapMethod(model, trait, method) ;
return endModel(model);
}
}
......@@ -35,9 +35,9 @@ import org.genesys2.server.model.VersionedAuditedModel;
import org.genesys2.server.model.impl.User;
import org.genesys2.server.service.UserService;
import org.genesys2.server.servlet.controller.BaseController;
import org.bioversityinternational.model.germplasm.CCO;
import org.bioversityinternational.model.rdf.dc.DublinCore;
import org.bioversityinternational.model.rdf.dwc.DarwinCore;
import org.bioversityinternational.model.rdf.skos.SKOS;
/**
......@@ -77,6 +77,7 @@ public abstract class RdfBaseController extends BaseController {
model.setNsPrefix("rdfs", RDFS.getURI() );
model.setNsPrefix("dc", DC.getURI() );
model.setNsPrefix("dcterms", DublinCore.getURI() );
model.setNsPrefix("dwc", DarwinCore.getURI() );
model.setNsPrefix("skos", SKOS.getURI() );
model.setNsPrefix("cco", CCO.getURI() );
model.setNsPrefix("genesys", GENESYS_BASEURI+"/" );
......@@ -108,8 +109,28 @@ public abstract class RdfBaseController extends BaseController {
/*
* Method to create a subject Resource initialized with common core annotation.
*/
private Resource createResource(Model model, VersionedAuditedModel entity, String uri, String id, Boolean isProperty) {
// Same as following method but defaults to SKOS.Concept ...
private Resource createResource(
Model model,
VersionedAuditedModel entity,
String uri,
String id,
Boolean isProperty
) {
return createResource( model, entity, uri, id, isProperty, false ) ;
}
// This version checks a flag for SKOS:Collection status
private Resource createResource(
Model model,
VersionedAuditedModel entity,
String uri,
String id,
Boolean isProperty,
Boolean isCollection // SKOS type - true if isa SKOS:Collection
) {
if(isProperty)