diff --git a/pom.xml b/pom.xml index b969337b..92eb9306 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ baseCode baseCode baseCode - 1.1.10 + 1.1.11 2003 @@ -132,11 +132,6 @@ mtj 1.0.4 - - net.sourceforge.f2j - arpack_combined_all - 0.1 - @@ -178,6 +173,10 @@ org.slf4j slf4j-log4j12 + + icu4j + com.ibm.icu + @@ -378,7 +377,7 @@ maven-surefire-plugin 2.22.2 - -enableassertions -Xmx512m -Djava.awt.headless=true + -enableassertions -Xmx1024m -Djava.awt.headless=true target/surefire-reports true diff --git a/src/ubic/basecode/ontology/OntologyLoader.java b/src/ubic/basecode/ontology/OntologyLoader.java index bac123c9..ef18459e 100644 --- a/src/ubic/basecode/ontology/OntologyLoader.java +++ b/src/ubic/basecode/ontology/OntologyLoader.java @@ -1,8 +1,8 @@ /* * The baseCode project - * + * * Copyright (c) 2010 University of British Columbia - * + * * 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 @@ -18,49 +18,29 @@ */ package ubic.basecode.ontology; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; -import java.util.Collection; -import java.util.HashSet; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.time.StopWatch; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.hp.hpl.jena.ontology.Individual; -import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.ModelMaker; -import com.hp.hpl.jena.util.iterator.ExtendedIterator; - -import ubic.basecode.ontology.model.OntologyIndividual; -import ubic.basecode.ontology.model.OntologyIndividualImpl; -import ubic.basecode.ontology.model.OntologyProperty; -import ubic.basecode.ontology.model.OntologyResource; -import ubic.basecode.ontology.model.OntologyTerm; -import ubic.basecode.ontology.model.OntologyTermImpl; -import ubic.basecode.ontology.model.PropertyFactory; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.StopWatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import ubic.basecode.util.Configuration; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + /** * Reads ontologies from OWL resources - * - * @author paul + * + * @author paul */ public class OntologyLoader { @@ -69,133 +49,37 @@ public class OntologyLoader { private static final String OLD_CACHE_SUFFIX = ".old"; private static final String TMP_CACHE_SUFFIX = ".tmp"; - /** - * @param url - * @param model - * @return - */ - public static Collection initialize( String url, OntModel model ) { - - Collection result = new HashSet<>(); - - ExtendedIterator classIt = model.listClasses(); - int count = 0; - log.debug( "Reading classes for ontology: " + url ); - while ( classIt.hasNext() ) { - OntClass element = classIt.next(); - if ( element.isAnon() ) continue; - OntologyTerm ontologyTerm = new OntologyTermImpl( element ); - result.add( ontologyTerm ); - if ( ++count % 1000 == 0 ) { - log.debug( "Loaded " + count + " terms, last was " + ontologyTerm ); - } - } - - log.debug( "Loaded " + count + " terms" ); - - ExtendedIterator propIt = model.listObjectProperties(); - count = 0; - log.debug( "Reading object properties..." ); - while ( propIt.hasNext() ) { - com.hp.hpl.jena.ontology.ObjectProperty element = propIt.next(); - OntologyProperty ontologyTerm = PropertyFactory.asProperty( element ); - if ( ontologyTerm == null ) continue; // couldn't be converted for some reason. - result.add( ontologyTerm ); - if ( ++count % 1000 == 0 ) { - log.debug( "Loaded " + count + " object properties, last was " + ontologyTerm ); - } - } - - ExtendedIterator dtPropIt = model.listDatatypeProperties(); - log.debug( "Reading datatype properties..." ); - while ( dtPropIt.hasNext() ) { - com.hp.hpl.jena.ontology.DatatypeProperty element = dtPropIt.next(); - OntologyProperty ontologyTerm = PropertyFactory.asProperty( element ); - if ( ontologyTerm == null ) continue; // couldn't be converted for some reason. - result.add( ontologyTerm ); - if ( ++count % 1000 == 0 ) { - log.debug( "Loaded " + count + " datatype properties, last was " + ontologyTerm ); - } - } - - log.debug( "Loaded " + count + " properties" ); - - ExtendedIterator indiIt = model.listIndividuals(); - count = 0; - log.debug( "Reading individuals..." ); - while ( indiIt.hasNext() ) { - Individual element = indiIt.next(); - if ( element.isAnon() ) continue; - OntologyIndividual ontologyTerm = new OntologyIndividualImpl( element ); - result.add( ontologyTerm ); - if ( ++count % 1000 == 0 ) { - log.debug( "Loaded " + count + " individuals, last was " + ontologyTerm ); - } - } - log.debug( "Loaded " + count + " individuals" ); - return result; - } - /** * Load an ontology into memory. Use this type of model when fast access is critical and memory is available. - * - * @param is - * @param url, used as a key - * @param spec - * @return */ - public static OntModel loadMemoryModel( InputStream is, String url, OntModelSpec spec ) { - OntModel model = getMemoryModel( url, spec ); + public static OntModel loadMemoryModel( InputStream is, String url ) { + OntModel model = getMemoryModel( url ); model.read( is, null ); return model; } - /** - * Load an ontology into memory. Use this type of model when fast access is critical and memory is available. Uses - * OWL_MEM_TRANS_INF - * - * @param url - * @return - */ - public static OntModel loadMemoryModel( String url ) { - return loadMemoryModel( url, OntModelSpec.OWL_MEM_TRANS_INF ); - } - - /** - * Load an ontology into memory. Use this type of model when fast access is critical and memory is available. Uses - * OWL_MEM_TRANS_INF - * If load from URL fails, attempt to load from disk cache under @cacheName. - * - * @param url - * @return - */ - public static OntModel loadMemoryModel( String url, String cacheName ) { - return loadMemoryModel( url, OntModelSpec.OWL_MEM_TRANS_INF, cacheName ); - } - /** * Load an ontology into memory. Use this type of model when fast access is critical and memory is available. - * - * @param url - * @return + * + * @see #loadMemoryModel(String, String) */ - public static OntModel loadMemoryModel( String url, OntModelSpec spec ) { - return loadMemoryModel( url, spec, null ); + public static OntModel loadMemoryModel( String url ) { + return loadMemoryModel( url, null ); } /** * Load an ontology into memory. Use this type of model when fast access is critical and memory is available. * If load from URL fails, attempt to load from disk cache under @cacheName. - * - * @param url - * @param spec e.g. OWL_MEM_TRANS_INF - * @param cacheName unique name of this ontology, will be used to load from disk in case of failed url connection - * @return + *

+ * Uses {@link OntModelSpec#OWL_MEM_TRANS_INF}. + * + * @param url a URL where the OWL file is stored + * @param cacheName unique name of this ontology, will be used to load from disk in case of failed url connection */ - public static OntModel loadMemoryModel( String url, OntModelSpec spec, String cacheName ) { + public static OntModel loadMemoryModel( String url, String cacheName ) { StopWatch timer = new StopWatch(); timer.start(); - OntModel model = getMemoryModel( url, spec ); + OntModel model = getMemoryModel( url ); URLConnection urlc = null; int tries = 0; @@ -242,7 +126,7 @@ public static OntModel loadMemoryModel( String url, OntModelSpec spec, String ca } if ( urlc != null ) { - try (InputStream in = urlc.getInputStream();) { + try ( InputStream in = urlc.getInputStream(); ) { Reader reader; if ( cacheName != null ) { // write tmp to disk @@ -261,7 +145,7 @@ public static OntModel loadMemoryModel( String url, OntModelSpec spec, String ca } assert reader != null; - try (BufferedReader buf = new BufferedReader( reader );) { + try ( BufferedReader buf = new BufferedReader( reader ); ) { model.read( buf, url ); } @@ -286,7 +170,7 @@ public static OntModel loadMemoryModel( String url, OntModelSpec spec, String ca } if ( f.exists() && !f.isDirectory() ) { - try (BufferedReader buf = new BufferedReader( new FileReader( f ) );) { + try ( BufferedReader buf = new BufferedReader( new FileReader( f ) ); ) { model.read( buf, url ); // We successfully loaded the cached ontology. Copy the loaded ontology to oldFile // so that we don't recreate indices during initialization based on a false change in @@ -359,25 +243,14 @@ public static boolean deleteOldCache( String cacheName ) { return false; } - /** - * Get model that is entirely in memory with default OntModelSpec.OWL_MEM_RDFS_INF. - * - * @param url - * @return - */ - static OntModel getMemoryModel( String url ) { - return getMemoryModel( url, OntModelSpec.OWL_MEM_RDFS_INF ); - } - /** * Get model that is entirely in memory. - * - * @param url - * @param specification + * + * @param url * @return */ - static OntModel getMemoryModel( String url, OntModelSpec specification ) { - OntModelSpec spec = new OntModelSpec( specification ); + private static OntModel getMemoryModel( String url ) { + OntModelSpec spec = new OntModelSpec( OntModelSpec.OWL_MEM_TRANS_INF ); ModelMaker maker = ModelFactory.createMemModelMaker(); Model base = maker.createModel( url, false ); spec.setImportModelMaker( maker ); @@ -389,7 +262,7 @@ static OntModel getMemoryModel( String url, OntModelSpec specification ) { } /** - * @param name + * @param name * @return */ public static File getDiskCachePath( String name ) { diff --git a/src/ubic/basecode/ontology/model/OntologyTerm.java b/src/ubic/basecode/ontology/model/OntologyTerm.java index 4717fc57..d31b38bf 100644 --- a/src/ubic/basecode/ontology/model/OntologyTerm.java +++ b/src/ubic/basecode/ontology/model/OntologyTerm.java @@ -1,8 +1,8 @@ /* * The basecode project - * + * * Copyright (c) 2007-2019 Columbia University - * + * * 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 @@ -22,48 +22,53 @@ /** * @author Paul - * */ public interface OntologyTerm extends OntologyResource { - public Collection getAlternativeIds(); + Collection getAlternativeIds(); - public Collection getAnnotations(); + Collection getAnnotations(); + + Collection getChildren( boolean direct ); /** * @param direct return only the immediate children; if false, return all of them down to the leaves. + * @param includePartOf include terms matched via * @return */ - public Collection getChildren( boolean direct ); + Collection getChildren( boolean direct, boolean includePartOf ); - public String getComment(); + String getComment(); - public Collection getIndividuals(); + Collection getIndividuals(); - public Collection getIndividuals( boolean direct ); + Collection getIndividuals( boolean direct ); - public String getLocalName(); + String getLocalName(); - public Object getModel(); + Object getModel(); /** * Note that any restriction superclasses are not returned, unless they are has_proper_part - * + * * @param direct * @return */ - public Collection getParents( boolean direct ); + Collection getParents( boolean direct ); - public Collection getRestrictions(); + Collection getParents( boolean direct, boolean includePartOf ); - public String getTerm(); + Collection getRestrictions(); - @Override - public String getUri(); + String getTerm(); - public boolean isRoot(); + @Override + String getUri(); - /** check to see if the term is obsolete, if it is it should not be used */ - public boolean isTermObsolete(); + boolean isRoot(); + /** + * check to see if the term is obsolete, if it is it should not be used + */ + boolean isTermObsolete(); } diff --git a/src/ubic/basecode/ontology/model/OntologyTermImpl.java b/src/ubic/basecode/ontology/model/OntologyTermImpl.java index 0d5186a1..6ce80a76 100644 --- a/src/ubic/basecode/ontology/model/OntologyTermImpl.java +++ b/src/ubic/basecode/ontology/model/OntologyTermImpl.java @@ -14,27 +14,14 @@ */ package ubic.basecode.ontology.model; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang3.ObjectUtils; - -import com.hp.hpl.jena.ontology.AllValuesFromRestriction; -import com.hp.hpl.jena.ontology.ConversionException; -import com.hp.hpl.jena.ontology.Individual; -import com.hp.hpl.jena.ontology.OntClass; -import com.hp.hpl.jena.ontology.OntProperty; -import com.hp.hpl.jena.ontology.OntResource; -import com.hp.hpl.jena.ontology.Restriction; -import com.hp.hpl.jena.ontology.SomeValuesFromRestriction; -import com.hp.hpl.jena.rdf.model.Property; -import com.hp.hpl.jena.rdf.model.RDFNode; -import com.hp.hpl.jena.rdf.model.Resource; -import com.hp.hpl.jena.rdf.model.ResourceFactory; -import com.hp.hpl.jena.rdf.model.Statement; -import com.hp.hpl.jena.rdf.model.StmtIterator; +import com.hp.hpl.jena.ontology.*; +import com.hp.hpl.jena.rdf.model.*; import com.hp.hpl.jena.util.iterator.ExtendedIterator; +import com.hp.hpl.jena.util.iterator.Filter; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; /** * Represents a class in an ontology @@ -45,30 +32,44 @@ public class OntologyTermImpl extends AbstractOntologyResource implements Ontolo private static final String HAS_ALTERNATE_ID = "http://www.geneontology.org/formats/oboInOwl#hasAlternativeId"; private static final String NOTHING = "http://www.w3.org/2002/07/owl#Nothing"; - private static Set REJECT_PARENT_URI = new HashSet<>(); /** - * + * Properties through which propagation is allowed for {@link #getParents(boolean)} */ - private static final long serialVersionUID = 1L; + private static final Set PROPAGATE_PARENT_URIS = new HashSet<>(); + + private static final Set REJECT_PARENT_URIS = new HashSet<>(); /** - * Should has_proper_part be used to indicate additional parent/child relations. + * */ - private static final boolean USE_PROPER_PART_RESTRICTIONS = true; - static { - REJECT_PARENT_URI.add( "http://www.ifomis.org/bfo/1.1/snap#IndependentContinuant" ); - REJECT_PARENT_URI.add( "http://www.ifomis.org/bfo/1.1/snap#Continuant" ); - REJECT_PARENT_URI.add( "http://www.ifomis.org/bfo/1.1/snap#MaterialEntity" ); + private static final long serialVersionUID = 1L; - // anatomical entity - REJECT_PARENT_URI.add( "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_6" ); + static { + CollectionUtils.addAll( PROPAGATE_PARENT_URIS, + "http://www.obofoundry.org/ro/ro.owl#proper_part_of", + "http://purl.obolibrary.org/obo/BFO_0000050" // part of + ); + CollectionUtils.addAll( REJECT_PARENT_URIS, + "http://www.ifomis.org/bfo/1.1/snap#IndependentContinuant", + "http://www.ifomis.org/bfo/1.1/snap#Continuant", + "http://www.ifomis.org/bfo/1.1/snap#MaterialEntity", + // anatomical entity + "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_6" ); } private String label = null; private String localName = null; - private transient OntClass ontResource = null; + /** + * Ontology class underlying this term. + */ + private final transient OntClass ontResource; + + /** + * Extra sets of properties to use when navigating parents and children of a term. + */ + private final transient Set propagateParentsProperties; public OntologyTermImpl( OntClass resource ) { this.ontResource = resource; @@ -76,6 +77,12 @@ public OntologyTermImpl( OntClass resource ) { this.label = ontResource.getLabel( "EN" ); if ( this.label == null ) this.label = ontResource.getLabel( null ); this.localName = ontResource.getLocalName(); + this.propagateParentsProperties = PROPAGATE_PARENT_URIS.stream() + .map( uri -> resource.getModel().getProperty( uri ) ) + .filter( Objects::nonNull ) + .collect( Collectors.toSet() ); + } else { + this.propagateParentsProperties = Collections.emptySet(); } } @@ -88,9 +95,9 @@ public boolean equals( Object obj ) { final OntologyTermImpl that = ( OntologyTermImpl ) obj; if ( this.getUri() != null ) { - return ObjectUtils.equals( this.getUri(), that.getUri() ); + return Objects.equals( this.getUri(), that.getUri() ); } - return ObjectUtils.equals( this.getTerm(), that.getTerm() ); + return Objects.equals( this.getTerm(), that.getTerm() ); } @Override @@ -98,7 +105,8 @@ public Collection getAlternativeIds() { Collection results = new HashSet<>(); Property alternate = ResourceFactory.createProperty( HAS_ALTERNATE_ID ); - for ( StmtIterator it = this.ontResource.listProperties( alternate ); it.hasNext(); ) { + StmtIterator it = this.ontResource.listProperties( alternate ); + while ( it.hasNext() ) { Statement statement = it.next(); results.add( statement.asTriple().getMatchObject().getLiteralLexicalForm() ); } @@ -126,9 +134,80 @@ public Collection getAnnotations() { @Override public Collection getChildren( boolean direct ) { - Collection result = new HashSet<>(); - getChildren( direct, result ); - return result; + return getChildren( direct, true ); + } + + @Override + public Collection getChildren( boolean direct, boolean includePartOf ) { + Collection result = new HashSet<>(); + ExtendedIterator iterator = ontResource.listSubClasses( direct ) + .filterDrop( new EqualityByUriFilter( NOTHING ) ); + OntModel model = ontResource.getOntModel(); + + while ( iterator.hasNext() ) { + OntClass c = iterator.next(); + + // bnode + if ( c.getURI() == null ) + continue; + + result.add( c ); + } + + if ( includePartOf ) { + Property subClassOf = model.getProfile().SUB_CLASS_OF(); + ExtendedIterator restrictionsIterator = model.listRestrictions() + .filterKeep( new RestrictionWithPropertyAndValueFilter( propagateParentsProperties, ontResource ) ); + while ( restrictionsIterator.hasNext() ) { + Restriction r = restrictionsIterator.next(); + ResIterator ss = model.listResourcesWithProperty( subClassOf, r ); + while ( ss.hasNext() ) { + Resource s = ss.next(); + if ( s.getURI() != null ) { + OntClass o = model.getOntClass( s.getURI() ); + if ( o != null ) { + result.add( o ); + } + } + } + } + } + + return result.stream().map( OntologyTermImpl::new ).collect( Collectors.toSet() ); + } + + /** + * Filter that retain resources with the given URI. + */ + private static class EqualityByUriFilter extends Filter { + private final String uri; + + private EqualityByUriFilter( String uri ) { + this.uri = uri; + } + + @Override + public boolean accept( OntClass o ) { + return uri.equals( o.getURI() ); + } + } + + /** + * Filter that retain only the restrictions with any of the given properties and resource as value. + */ + private static class RestrictionWithPropertyAndValueFilter extends Filter { + private final Set properties; + private final Resource resource; + + private RestrictionWithPropertyAndValueFilter( Set properties, OntClass resource ) { + this.properties = properties; + this.resource = resource; + } + + @Override + public boolean accept( Restriction o ) { + return hasRestrictionValue( o, resource ) && properties.stream().anyMatch( o::onProperty ); + } } /* @@ -152,17 +231,15 @@ public Collection getIndividuals() { return getIndividuals( true ); } - /** - * @param direct - * @return - */ @Override public Collection getIndividuals( boolean direct ) { Collection inds = new HashSet<>(); ExtendedIterator iterator = this.ontResource.listInstances( direct ); while ( iterator.hasNext() ) { - Individual i = ( Individual ) iterator.next(); - inds.add( new OntologyIndividualImpl( i ) ); + OntResource r = iterator.next(); + if ( r.isIndividual() ) { + inds.add( new OntologyIndividualImpl( r.asIndividual() ) ); + } } return inds; } @@ -184,9 +261,49 @@ public Object getModel() { @Override public Collection getParents( boolean direct ) { - Collection result = new HashSet<>(); - this.getParents( direct, result ); - return result; + return getParents( direct, true ); + } + + @Override + public Collection getParents( boolean direct, boolean includePartOf ) { + Collection result = new HashSet<>(); + ExtendedIterator iterator; + Set excludeProperties; + iterator = ontResource.listSuperClasses( direct ); + excludeProperties = REJECT_PARENT_URIS; + + while ( iterator.hasNext() ) { + OntClass c = iterator.next(); + + // handles part of some {parent container} or part of all {parent container} + if ( includePartOf && c.isRestriction() ) { + Restriction r = c.asRestriction(); + if ( propagateParentsProperties.contains( r.getOnProperty() ) ) { + Resource value = getRestrictionValue( c.asRestriction() ); + if ( value instanceof OntClass ) { + c = ( OntClass ) value; + } else { + continue; + } + } + } + + // bnode + if ( c.getURI() == null ) + continue; + + // excluded terms + if ( excludeProperties.contains( c.getURI() ) ) + continue; + + // already visited + if ( result.contains( c ) ) + continue; + + result.add( c ); + } + + return result.stream().map( OntologyTermImpl::new ).collect( Collectors.toSet() ); } /** @@ -201,14 +318,9 @@ public Collection getRestrictions() { ExtendedIterator iterator = ontResource.listSuperClasses( false ); while ( iterator.hasNext() ) { OntClass c = iterator.next(); - Restriction r = null; - try { - r = c.asRestriction(); - result.add( RestrictionFactory.asRestriction( r ) ); - } catch ( Exception e ) { - + if ( c.isRestriction() ) { + result.add( RestrictionFactory.asRestriction( c.asRestriction() ) ); } - } // Check superclasses for any ADDITIONAL restrictions. @@ -221,9 +333,10 @@ public Collection getRestrictions() { } catch ( Exception e ) { // not a restriction, but a superclass that might have restrictions ExtendedIterator supClassesIt = c.listSuperClasses( false ); - loop: while ( supClassesIt.hasNext() ) { + loop: + while ( supClassesIt.hasNext() ) { OntClass sc = supClassesIt.next(); - Restriction sr = null; + Restriction sr; try { sr = sc.asRestriction(); @@ -253,7 +366,7 @@ public Collection getRestrictions() { */ @Override public String getTerm() { - String res = null; + String res; if ( this.label != null ) { res = this.label; } else if ( this.localName != null ) { @@ -322,11 +435,11 @@ public boolean isTermObsolete() { if ( parentOntologyTerm.getUri() != null && parentOntologyTerm.getUri().equalsIgnoreCase( - "http://bioontology.org/projects/ontologies/birnlex#_birnlex_retired_class" ) + "http://bioontology.org/projects/ontologies/birnlex#_birnlex_retired_class" ) || parentOntologyTerm - .getUri() - .equalsIgnoreCase( - "http://ontology.neuinfo.org/NIF/Backend/BIRNLex_annotation_properties.owl#_birnlex_retired_class" ) ) { + .getUri() + .equalsIgnoreCase( + "http://ontology.neuinfo.org/NIF/Backend/BIRNLex_annotation_properties.owl#_birnlex_retired_class" ) ) { return true; } } @@ -343,7 +456,7 @@ public boolean isTermObsolete() { RDFNode n = state.getObject(); if ( p.getLocalName().equalsIgnoreCase( "deprecated" ) ) { - if ( n.toString().indexOf( "true" ) != -1 ) { + if ( n.toString().contains( "true" ) ) { return true; } break; @@ -371,169 +484,23 @@ public String toString() { return res; } - protected OntologyTerm fromOntClass( OntClass ontClass ) { - return new OntologyTermImpl( ontClass ); - } - - /** - * @param direct - * @param work - */ - private void getChildren( boolean direct, Collection work ) { - - // get children by recursion, don't rely on the jena api. - ExtendedIterator iterator = ontResource.listSubClasses( true ); - while ( iterator.hasNext() ) { - OntClass c = iterator.next(); - // URI can be null if the ont is a bnode (no idea what it is, but we have to handle this) - // some reasoners will infer owl#Nothing as a subclass of everything - if ( c.getURI() == null || c.getURI().equals( NOTHING ) ) continue; - - if ( USE_PROPER_PART_RESTRICTIONS && c.isRestriction() ) { - - Restriction restriction = c.asRestriction(); - - OntProperty onProperty = restriction.getOnProperty(); - - if ( !onProperty.getURI().equals( "http://www.obofoundry.org/ro/ro.owl#has_proper_part" ) ) { - continue; - } - - Resource r = getRestrictionValue( restriction ); - if ( r == null ) continue; - - OntologyTerm child = fromOntClass( ( OntClass ) r ); - - // avoid risk of endless regression. - if ( !work.contains( child ) ) { - work.add( child ); - if ( !direct ) ( ( OntologyTermImpl ) child ).getChildren( false, work ); - } - } else { - OntologyTerm child = this.fromOntClass( c ); - work.add( child ); - if ( !direct ) ( ( OntologyTermImpl ) child ).getChildren( false, work ); - } - // log.info( c ); - } - - if ( USE_PROPER_PART_RESTRICTIONS ) { - ExtendedIterator sciterator = this.ontResource.listSuperClasses( true ); - while ( sciterator.hasNext() ) { - OntClass c = sciterator.next(); - if ( !c.isRestriction() ) { - continue; - } - - Restriction restriction = c.asRestriction(); - - try { - OntProperty onProperty = restriction.getOnProperty(); - if ( !onProperty.getURI().equals( "http://www.obofoundry.org/ro/ro.owl#has_proper_part" ) ) { - continue; - } - } catch ( ConversionException e ) { - continue; - } - - Resource r = getRestrictionValue( restriction ); - if ( r == null ) continue; - - // if ( !( r instanceof OntClass ) ) { - // // means our owl file is incomplete, is in tests. - // log.info( r ); - // continue; - // } - - OntologyTerm child = fromOntClass( ( OntClass ) r ); - if ( !work.contains( child ) ) { - work.add( child ); - if ( !direct ) ( ( OntologyTermImpl ) child ).getChildren( false, work ); - } - - } - } - } - - /** - * @param direct - * @param work - */ - private void getParents( boolean direct, Collection work ) { - assert work != null; - if ( !ontResource.isClass() ) { - return; - } - - ExtendedIterator iterator = ontResource.listSuperClasses( true ); - - while ( iterator.hasNext() ) { - - try { - OntClass c = iterator.next(); - - if ( USE_PROPER_PART_RESTRICTIONS && c.isRestriction() ) { - Restriction restriction = c.asRestriction(); - - OntProperty onProperty = restriction.getOnProperty(); - - assert onProperty != null; - - // We ignore this... hack. - if ( !onProperty.getURI().equals( "http://www.obofoundry.org/ro/ro.owl#proper_part_of" ) ) { - continue; - } - - Resource r = getRestrictionValue( restriction ); - - if ( r == null ) continue; - - assert r != null; - if ( log.isDebugEnabled() ) log.debug( " Some from:" + r + " " + onProperty.getURI() ); - - OntologyTerm parent = fromOntClass( ( OntClass ) r ); - - if ( REJECT_PARENT_URI.contains( parent.getUri() ) ) continue; - - // avoid endless regression - if ( !work.contains( parent ) ) { - work.add( parent ); - if ( !direct ) ( ( OntologyTermImpl ) parent ).getParents( direct, work ); - } - - } else { - // not a restriction. - OntologyTerm parent = this.fromOntClass( c ); - - if ( REJECT_PARENT_URI.contains( parent.getUri() ) ) continue; - - if ( !work.contains( parent ) ) { - work.add( parent ); - if ( !direct ) { - // recurse. - ( ( OntologyTermImpl ) parent ).getParents( direct, work ); - } - } - } - } catch ( ConversionException e ) { - if ( log.isDebugEnabled() ) log.debug( e.getMessage() ); - continue; - } - + private static Resource getRestrictionValue( Restriction r ) { + if ( r.isSomeValuesFromRestriction() ) { + return r.asSomeValuesFromRestriction().getSomeValuesFrom(); + } else if ( r.isAllValuesFromRestriction() ) { + return r.asAllValuesFromRestriction().getAllValuesFrom(); + } else { + return null; } } - private Resource getRestrictionValue( Restriction restriction ) { - Resource r = null; - - if ( restriction.isSomeValuesFromRestriction() ) { - SomeValuesFromRestriction some = restriction.asSomeValuesFromRestriction(); - r = some.getSomeValuesFrom(); - } else if ( restriction.isAllValuesFromRestriction() ) { - AllValuesFromRestriction allValues = restriction.asAllValuesFromRestriction(); - r = allValues.getAllValuesFrom(); + private static boolean hasRestrictionValue( Restriction r, Resource value ) { + if ( r.isSomeValuesFromRestriction() ) { + return r.asSomeValuesFromRestriction().hasSomeValuesFrom( value ); + } else if ( r.isAllValuesFromRestriction() ) { + return r.asAllValuesFromRestriction().hasAllValuesFrom( value ); + } else { + return false; } - return r; } - } diff --git a/src/ubic/basecode/ontology/providers/AbstractOntologyMemoryBackedService.java b/src/ubic/basecode/ontology/providers/AbstractOntologyMemoryBackedService.java index 34bc3acf..2470d05b 100644 --- a/src/ubic/basecode/ontology/providers/AbstractOntologyMemoryBackedService.java +++ b/src/ubic/basecode/ontology/providers/AbstractOntologyMemoryBackedService.java @@ -1,97 +1,30 @@ /* * The baseCode project - * + * * Copyright (c) 2013 University of British Columbia - * + * * 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 ubic.basecode.ontology.providers; -import java.io.IOException; -import java.io.InputStream; - -import ubic.basecode.ontology.OntologyLoader; -import ubic.basecode.ontology.search.OntologyIndexer; - import com.hp.hpl.jena.ontology.OntModel; -import com.hp.hpl.jena.ontology.OntModelSpec; +import ubic.basecode.ontology.OntologyLoader; /** * This class has some stuff that's specific to in-memory ontologies. Unlike database backed ontologies we don't use a * pool keeping only one instance of model in memory. - * + * * @author paul */ public abstract class AbstractOntologyMemoryBackedService extends AbstractOntologyService { - /** - * For testing! Overrides normal way of loading the ontology. This does not index the ontology unless 'force' is - * true (if there is an existing index, it will be used) - * - * @param is - * @param forceIndex initialize the index. Otherwise it will only be initialized if it doesn't exist. - * @throws IOException - */ - public synchronized void loadTermsInNameSpace( InputStream is, boolean forceIndex ) { - synchronized ( isInitialized ) { - this.indexReady.set( false ); - this.modelReady.set( false ); - this.isInitialized.set( false ); - this.cacheReady.set( false ); - } - - if ( initializationThread.isAlive() ) { - log.warn( this.getOntologyName() + " initialization is already running, trying to cancel ..." ); - initializationThread.cancel(); - - // wait for the thread to die. - int maxWait = 10; - int wait = 0; - while ( initializationThread.isAlive() ) { - try { - Thread.sleep( 5000 ); - log.warn( "Waiting for auto-initialization to stop so manual initialization can begin ..." ); - } catch ( InterruptedException e ) { - // no-op. - } - if ( ++wait >= maxWait ) { - log.error( "Got tired of waiting" ); - break; - } - if ( initializationThread.isInterrupted() ) { - log.warn( "Got interrupt." ); - break; - } - } - } - - if ( this.terms != null ) this.terms.clear(); - if ( this.individuals != null ) this.individuals.clear(); - - this.model = OntologyLoader.loadMemoryModel( is, this.getOntologyUrl(), OntModelSpec.OWL_MEM ); - this.index = OntologyIndexer.getSubjectIndex( getOntologyName() ); - if ( index == null || forceIndex ) { - this.index = OntologyIndexer.indexOntology( getOntologyName(), model, true /* force */ ); - } - - addTerms( OntologyLoader.initialize( this.getOntologyUrl(), model ) ); - - synchronized ( isInitialized ) { - indexReady.set( this.index != null ); - cacheReady.set( true ); - modelReady.set( true ); - isInitialized.set( true ); - } - log.info( this.getClass().getSimpleName() + " ready" ); - } - @Override protected synchronized OntModel loadModel() { return OntologyLoader.loadMemoryModel( this.getOntologyUrl(), this.getOntologyName() ); diff --git a/src/ubic/basecode/ontology/providers/AbstractOntologyService.java b/src/ubic/basecode/ontology/providers/AbstractOntologyService.java index c31566bf..42ae11c5 100644 --- a/src/ubic/basecode/ontology/providers/AbstractOntologyService.java +++ b/src/ubic/basecode/ontology/providers/AbstractOntologyService.java @@ -19,166 +19,132 @@ package ubic.basecode.ontology.providers; -import java.io.IOException; -import java.lang.Thread.State; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - +import com.hp.hpl.jena.ontology.ObjectProperty; +import com.hp.hpl.jena.ontology.*; +import com.hp.hpl.jena.rdf.arp.ARPErrorNumbers; +import com.hp.hpl.jena.rdf.arp.ParseException; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.shared.JenaException; +import com.hp.hpl.jena.util.iterator.ExtendedIterator; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import com.hp.hpl.jena.ontology.OntModel; - import ubic.basecode.ontology.OntologyLoader; -import ubic.basecode.ontology.model.OntologyIndividual; -import ubic.basecode.ontology.model.OntologyResource; -import ubic.basecode.ontology.model.OntologyTerm; +import ubic.basecode.ontology.model.*; import ubic.basecode.ontology.search.OntologyIndexer; import ubic.basecode.ontology.search.OntologySearch; import ubic.basecode.ontology.search.OntologySearchException; import ubic.basecode.ontology.search.SearchIndex; import ubic.basecode.util.Configuration; +import java.io.InputStream; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + /** * @author kelsey */ -public abstract class AbstractOntologyService { +@SuppressWarnings("unused") +public abstract class AbstractOntologyService implements OntologyService { - protected class OntologyInitializationThread extends Thread { + protected static Logger log = LoggerFactory.getLogger( AbstractOntologyService.class ); - AtomicBoolean cancel = new AtomicBoolean( false ); + /** + * Lock used to prevent reads while the ontology is being initialized. + */ + private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); - private boolean forceReindexing = false; + /* internal state protected by rwLock */ + private OntModel model; + private Map alternativeIDs; + private final Map termCache = new ConcurrentHashMap<>( 1024 ); + private SearchIndex index; - public OntologyInitializationThread( boolean forceRefresh ) { - super(); - this.forceReindexing = forceRefresh; - } + private boolean isInitialized = false; - public void cancel() { - this.cancel.set( true ); - this.interrupt(); + @Override + public void initialize( boolean forceLoad, boolean forceIndexing ) { + if ( !forceLoad && isInitialized ) { + log.warn( getOntologyName() + " is already loaded, and force=false, not restarting" ); + return; } - public boolean isCancelled() { - return cancel.get(); - } + boolean loadOntology = isEnabled(); - public boolean isForceReindexing() { - return forceReindexing; + // If loading ontologies is disabled in the configuration, return + if ( !forceLoad && !loadOntology ) { + log.debug( "Loading " + getOntologyName() + " is disabled (force=" + forceLoad + ", " + "Configuration load." + getOntologyName() + "=" + loadOntology + ")" ); + return; } - @Override - public void run() { - - terms = new HashMap<>(); - individuals = new HashMap<>(); - - if ( isCancelled() ) { - log.warn( "Cancelled initialization" ); - return; - } - - log.info( "Loading ontology: " + getOntologyName() + " from " + getOntologyUrl() + " ..." ); - StopWatch loadTime = new StopWatch(); - loadTime.start(); - - model = getModel(); // can take a while. - assert model != null; - - try { - - //Checks if the current ontology has changed since it was last loaded. - boolean changed = OntologyLoader.hasChanged( getOntologyName() ); - boolean indexExists = OntologyIndexer.getSubjectIndex( getOntologyName() ) != null; - - /* - * Indexing is slow, don't do it if we don't have to. - */ - index( forceReindexing || changed || !indexExists ); - - indexReady.set( true ); - - if ( isCancelled() ) { - log.error( "Cancelled initialization" ); - return; - } - - /* - * This creates a cache of URI (String) --> OntologyTerms. ?? Does Jena provide an easier way to do - * this? - */ - - loadTermsInNameSpace( getOntologyUrl(), model ); - - cleanup(); - - cacheReady.set( true ); - - isInitialized.set( true ); - loadTime.stop(); - - log.info( "Finished loading " + getOntologyName() + " in " + String.format( "%.2f", loadTime.getTime() / 1000.0 ) - + "s" ); - - } catch ( Exception e ) { - log.error( e.getMessage(), e ); - isInitialized.set( false ); - } finally { - // no-op - } + // Detect configuration problems. + if ( StringUtils.isBlank( this.getOntologyUrl() ) ) { + throw new IllegalStateException( "URL not defined, ontology cannot be loaded (" + this.getClass().getSimpleName() + ")" ); } - public void setForceReindexing( boolean forceReindexing ) { - this.forceReindexing = forceReindexing; + // This thread indexes ontology and creates local cache for uri->ontology terms mappings. + if ( !forceIndexing ) { + log.info( getOntologyName() + " index will *not* be refreshed unless the ontology " + "has changed or the index is misssing" ); } - private void cleanup() { - OntologyLoader.deleteOldCache( getOntologyName() ); - } - } + log.info( "Loading ontology: " + getOntologyName() + " from " + getOntologyUrl() + " ..." ); + StopWatch loadTime = StopWatch.createStarted(); - protected static Logger log = LoggerFactory.getLogger( AbstractOntologyService.class ); + // use temporary variables so we can minimize the critical region for replacing the service's state + Map terms = new HashMap<>(); + Map individuals = new HashMap<>(); + OntModel model; + SearchIndex index; - protected AtomicBoolean cacheReady = new AtomicBoolean( false ); + if ( Thread.currentThread().isInterrupted() ) { + log.warn( String.format( "The current thread is interrupted, initialization of %s will be stop.", getOntologyName() ) ); + return; + } - protected SearchIndex index; + model = loadModel(); // can take a while. + assert model != null; - protected AtomicBoolean indexReady = new AtomicBoolean( false ); - protected Map individuals; + //Checks if the current ontology has changed since it was last loaded. + boolean changed = OntologyLoader.hasChanged( getOntologyName() ); + boolean indexExists = OntologyIndexer.getSubjectIndex( getOntologyName() ) != null; + boolean forceReindexing = forceLoad && forceIndexing; - protected OntologyInitializationThread initializationThread; - protected AtomicBoolean isInitialized = new AtomicBoolean( false ); - protected OntModel model = null; + /* + * Indexing is slow, don't do it if we don't have to. + */ + boolean force = forceReindexing || changed || !indexExists; - protected AtomicBoolean modelReady = new AtomicBoolean( false ); + index = OntologyIndexer.indexOntology( getOntologyName(), model, force ); - protected Map terms = null; + if ( Thread.currentThread().isInterrupted() ) { + log.warn( String.format( "The current thread is interrupted, initialization of %s will be stop.", getOntologyName() ) ); + return; + } - private Map alternativeIDs = new HashMap<>(); + Lock lock = rwLock.writeLock(); + try { + lock.lock(); + this.model = model; + this.termCache.clear(); + this.index = index; + this.isInitialized = true; + } finally { + lock.unlock(); + } - /** - * - */ - public AbstractOntologyService() { - super(); + // now that the terms have been replaced, we can clear old caches + OntologyLoader.deleteOldCache( getOntologyName() ); - initializationThread = new OntologyInitializationThread( false ); - initializationThread.setName( getOntologyName() + "_load_thread_" + RandomStringUtils.randomAlphanumeric( 5 ) ); - // To prevent VM from waiting on this thread to shutdown (if shutting down). - initializationThread.setDaemon( true ); + loadTime.stop(); + log.info( String.format( "Finished loading %s in %ss", getOntologyName(), String.format( "%.2f", loadTime.getTime() / 1000.0 ) ) ); } - // private boolean enabled = false; - /** * Do not do this except before re-indexing. */ @@ -187,348 +153,368 @@ public void closeIndex() { index.close(); } - /** - * Looks for any OntologyIndividuals that match the given search string. - * - * @param search - * @return - */ + @Override public Collection findIndividuals( String search ) throws OntologySearchException { - - if ( !isOntologyLoaded() ) return null; - - if ( index == null ) { - log.warn( "attempt to search " + this.getOntologyName() + " when index is null" ); - return null; + Lock lock = rwLock.readLock(); + try { + lock.lock(); + if ( !isInitialized ) { + log.warn( String.format( "Ontology %s is not ready, no individuals will be returned.", getOntologyName() ) ); + return Collections.emptySet(); + } + if ( index == null ) { + log.warn( "attempt to search " + this.getOntologyName() + " when index is null" ); + return Collections.emptySet(); + } + return OntologySearch.matchIndividuals( model, index, search ); + } finally { + lock.unlock(); } - - OntModel m = getModel(); - - Collection indis = OntologySearch.matchIndividuals( m, index, search ); - - return indis; } - /** - * Looks for any OntologyIndividuals or ontologyTerms that match the given search string - * - * @param search - * @return results, or an empty collection if the results are empty OR the ontology is not available to be - * searched. - */ + @Override public Collection findResources( String searchString ) throws OntologySearchException { - - if ( !isOntologyLoaded() ) { - log.warn( "Ontology is not ready: " + this.getClass() ); - return new HashSet<>(); + Lock lock = rwLock.readLock(); + try { + lock.lock(); + if ( !isInitialized ) { + log.warn( String.format( "Ontology %s is not ready, no resources will be returned.", getOntologyName() ) ); + return Collections.emptySet(); + } + if ( index == null ) { + log.warn( "attempt to search " + this.getOntologyName() + " when index is null" ); + return Collections.emptySet(); + } + return OntologySearch.matchResources( model, index, searchString ); + } finally { + lock.unlock(); } - - assert index != null : "attempt to search " + this.getOntologyName() + " when index is null"; - - OntModel m = getModel(); - - Collection results = OntologySearch.matchResources( m, index, searchString ); - - return results; } - /** - * Looks for any ontologyTerms that match the given search string. Obsolete terms are filtered out. - * - * @param search - * @return - */ + @Override public Collection findTerm( String search ) throws OntologySearchException { - - if ( !isOntologyLoaded() ) return new HashSet<>(); - - if ( log.isDebugEnabled() ) log.debug( "Searching " + this.getOntologyName() + " for '" + search + "'" ); - - assert index != null : "attempt to search " + this.getOntologyName() + " when index is null"; - - OntModel m = getModel(); - - Collection matches = OntologySearch.matchClasses( m, index, search ); - - return matches; + if ( log.isDebugEnabled() ) log.debug( "Searching " + getOntologyName() + " for '" + search + "'" ); + Lock lock = rwLock.readLock(); + try { + lock.lock(); + if ( !isInitialized ) { + log.warn( String.format( "Ontology %s is not ready, no terms will be returned.", getOntologyName() ) ); + return Collections.emptySet(); + } + if ( index == null ) { + log.warn( "attempt to search " + this.getOntologyName() + " when index is null" ); + return Collections.emptySet(); + } + return OntologySearch.matchClasses( model, index, search ); + } finally { + lock.unlock(); + } } + @Override public OntologyTerm findUsingAlternativeId( String alternativeId ) { - - if ( alternativeIDs.isEmpty() ) { - log.info( "init search by alternativeID" ); - initSearchByAlternativeId(); - } - - if ( alternativeIDs.get( alternativeId ) != null ) { - return alternativeIDs.get( alternativeId ); + Lock lock = alternativeIDs != null ? rwLock.readLock() : rwLock.writeLock(); + try { + lock.lock(); + if ( !isInitialized ) { + log.warn( String.format( "Ontology %s is not ready, null will be returned for alternative ID match.", getOntologyName() ) ); + return null; + } + if ( alternativeIDs == null ) { + log.info( "init search by alternativeID" ); + initSearchByAlternativeId(); + } + String termUri = alternativeIDs.get( alternativeId ); + return termUri != null ? getTerm( termUri ) : null; + } finally { + lock.unlock(); } - - return null; } + @Override public Set getAllURIs() { - if ( terms == null ) return null; - return new HashSet<>( terms.keySet() ); + Lock lock = rwLock.readLock(); + try { + lock.lock(); + if ( !isInitialized ) { + log.warn( String.format( "Ontology %s is not ready, no term URIs will be returned.", getOntologyName() ) ); + return Collections.emptySet(); + } + Set allUris = new HashSet<>(); + ExtendedIterator iterator = model.listClasses(); + while ( iterator.hasNext() ) { + allUris.add( iterator.next().getURI() ); + } + ExtendedIterator it2 = model.listIndividuals(); + while ( it2.hasNext() ) { + allUris.add( it2.next().getURI() ); + } + return allUris; + } finally { + lock.unlock(); + } } - /** - * Looks through both Terms and Individuals for a OntologyResource that has a uri matching the uri given. If no - * OntologyTerm is found only then will ontologyIndividuals be searched. returns null if nothing is found. - * - * @param uri - * @return - */ + @Override public OntologyResource getResource( String uri ) { - - if ( ( uri == null ) || ( !isInitialized.get() ) ) return null; - - OntologyResource resource = terms.get( uri ); - - if ( resource == null ) resource = individuals.get( uri ); - - return resource; + if ( uri == null ) return null; + Lock lock = rwLock.readLock(); + try { + lock.lock(); + if ( !isInitialized ) { + return null; + } + OntologyResource res; + Resource resource = model.getResource( uri ); + if ( resource.getURI() == null ) { + return null; + } + if ( resource instanceof OntClass ) { + // use the cached term + res = getTermInternal( uri ); + } else if ( resource instanceof Individual ) { + res = new OntologyIndividualImpl( ( Individual ) resource ); + } else if ( resource instanceof OntProperty ) { + res = PropertyFactory.asProperty( ( ObjectProperty ) resource ); + } else { + res = null; + } + return res; + } finally { + lock.unlock(); + } } - /** - * Looks for a OntologyTerm that has the match in URI given - * - * @param uri - * @return - */ + @Override public OntologyTerm getTerm( String uri ) { - - if ( !isInitialized.get() || terms == null ) return null; - if ( uri == null ) throw new IllegalArgumentException( "URI cannot be null" ); - - OntologyTerm term = terms.get( uri ); - - return term; + Lock lock = rwLock.readLock(); + try { + lock.lock(); + if ( !isInitialized ) return null; + return getTermInternal( uri ); + } finally { + lock.unlock(); + } } - /** - * @param uri - * @return - */ + @Override public Collection getTermIndividuals( String uri ) { - - if ( terms == null ) { - log.warn( "No term for URI=" + uri + " in " + this.getOntologyName() - + " no terms loaded; make sure ontology is loaded and uri is valid" ); - return new HashSet<>(); - } - - OntologyTerm term = terms.get( uri ); - if ( term == null ) { - /* - * Either the ontology hasn't been loaded, or the id was not valid. - */ - log.warn( "No term for URI=" + uri + " in " + this.getOntologyName() - + "; make sure ontology is loaded and uri is valid" ); - return new HashSet<>(); + Lock lock = rwLock.readLock(); + try { + lock.lock(); + if ( !isInitialized ) { + return Collections.emptySet(); + } + OntologyTerm term = getTermInternal( uri ); + if ( term == null ) { + /* + * Either the ontology hasn't been loaded, or the id was not valid. + */ + log.warn( "No term for URI=" + uri + " in " + this.getOntologyName() + "; make sure ontology is loaded and uri is valid" ); + return new HashSet<>(); + } + return term.getIndividuals( true ); + } finally { + lock.unlock(); } - return term.getIndividuals( true ); - } - /** - * Create the search index. - * - * @param force - */ - public void index( boolean force ) { - StopWatch timer = new StopWatch(); - timer.start(); - OntModel m = getModel(); - assert m != null; - - index = OntologyIndexer.indexOntology( getOntologyName(), m, force ); - - } - - /** - * @return - */ + @Override public boolean isEnabled() { - if ( isOntologyLoaded() ) return true; // could have forced, without setting config + // quick path: just lookup the configuration String configParameter = "load." + getOntologyName(); - return Configuration.getBoolean( configParameter ); - } - - public boolean isInitializationThreadAlive() { - return initializationThread.isAlive(); + if ( Configuration.getBoolean( configParameter ) ) { + return true; + } + // could have forced, without setting config + Lock lock = rwLock.readLock(); + try { + lock.lock(); + return isInitialized; + } finally { + lock.unlock(); + } } - /** - * Used for determining if the Ontology has finished loading into memory. Although calls like getParents, - * getChildren will still work (its much faster once the ontologies have been preloaded into memory.) - * - * @returns boolean - */ + @Override public boolean isOntologyLoaded() { - return isInitialized.get(); + // it's fine not to use the read lock here + return isInitialized; } - /** - * - * @param forceLoad - * @param forceIndexing If forceLoad is also true, indexing will be performed. If you know the index is - * up to date, there's no need to do it again. Normally indexing is only done if there is no - * index, or if the ontology has changed since last loaded. - */ - public void startInitializationThread( boolean forceLoad, boolean forceIndexing ) { - assert initializationThread != null; - synchronized ( initializationThread ) { - if ( initializationThread.isAlive() ) { - log.warn( getOntologyName() + " initialization is already running, not restarting." ); - return; - } else if ( initializationThread.isInterrupted() ) { - log.warn( getOntologyName() + " initialization was interrupted, not restarting." ); - return; - } else if ( !initializationThread.getState().equals( State.NEW ) ) { - log.warn( getOntologyName() + " initialization was not ready to run: state=" - + initializationThread.getState() + ", not restarting." ); - return; - } - - if ( !forceLoad && this.isOntologyLoaded() ) { - log.warn( getOntologyName() + " is already loaded, and force=false, not restarting" ); - return; - } - - boolean loadOntology = isEnabled(); + private Thread initializationThread = null; - // If loading ontologies is disabled in the configuration, return - if ( !forceLoad && !loadOntology ) { - log.debug( "Loading " + getOntologyName() + " is disabled (force=" + forceLoad + ", " - + "Configuration load." + getOntologyName() + "=" + loadOntology + ")" ); - return; + @Override + public synchronized void startInitializationThread( boolean forceLoad, boolean forceIndexing ) { + if ( initializationThread != null && initializationThread.isAlive() ) { + log.warn( String.format( " Initialization thread for %s is currently running, not restarting.", getOntologyName() ) ); + return; + } + // create and start the initialization thread + initializationThread = new Thread( () -> { + try { + this.initialize( forceLoad, forceIndexing ); + } catch ( JenaException e ) { + if ( !( e.getCause() instanceof ParseException ) || ( ( ParseException ) e.getCause() ).getErrorNumber() != ARPErrorNumbers.ERR_INTERRUPTED ) { + throw e; + } + } catch ( Exception e ) { + log.error( e.getMessage(), e ); + this.isInitialized = false; } + }, getOntologyName() + "_load_thread_" + RandomStringUtils.randomAlphanumeric( 5 ) ); + // To prevent VM from waiting on this thread to shutdown (if shutting down). + initializationThread.setDaemon( true ); + initializationThread.start(); + } - // Detect configuration problems. - if ( StringUtils.isBlank( this.getOntologyUrl() ) ) { - throw new IllegalStateException( "URL not defined, ontology cannot be loaded (" - + this.getClass().getSimpleName() + ")" ); - } + @Override + public boolean isInitializationThreadAlive() { + return initializationThread != null && initializationThread.isAlive(); + } - // This thread indexes ontology and creates local cache for uri->ontology terms mappings. - if ( !forceIndexing ) { - log.info( getOntologyName() + " index will *not* be refreshed unless the ontology " - + "has changed or the index is misssing" ); - } - initializationThread.setForceReindexing( forceLoad && forceIndexing ); - initializationThread.start(); - } + @Override + public boolean isInitializationThreadCancelled() { + return initializationThread != null && initializationThread.isInterrupted(); } /** * Cancel the initialization thread. */ + @Override public void cancelInitializationThread() { - initializationThread.cancel(); - } - - /** - * @param newTerms - */ - protected void addTerms( Collection newTerms ) { - - if ( newTerms == null || newTerms.isEmpty() ) { - log.warn( "No terms!" ); - return; - } - - if ( terms == null ) terms = new HashMap<>(); - if ( individuals == null ) individuals = new HashMap<>(); - - int i = 0; - for ( OntologyResource term : newTerms ) { - if ( term.getUri() == null ) continue; - if ( term instanceof OntologyTerm ) terms.put( term.getUri(), ( OntologyTerm ) term ); - if ( term instanceof OntologyIndividual ) individuals.put( term.getUri(), ( OntologyIndividual ) term ); - - if ( ++i % 1000 == 0 && initializationThread.isCancelled() ) { - log.error( "Cancelled initialization" ); - this.isInitialized.set( false ); - return; - } + if ( initializationThread == null ) { + throw new IllegalStateException( "The initialization thread has not started. Invoke startInitializationThread() first." ); } + initializationThread.interrupt(); } - protected synchronized OntModel getModel() { - if ( model == null ) { - model = loadModel(); + @Override + public void waitForInitializationThread() throws InterruptedException { + if ( initializationThread == null ) { + throw new IllegalStateException( "The initialization thread has not started. Invoke startInitializationThread() first." ); } - return model; + initializationThread.join(); } /** - * The simple name of the ontology. Used for indexing purposes. (ie this will determine the name of the underlying + * The simple getOntologyName() of the ontology. Used for indexing purposes. (ie this will determine the getOntologyName() of the underlying * index for searching the ontology) - * - * @return */ protected abstract String getOntologyName(); /** - * Defines the location of the ontology eg: http://mged.sourceforge.net/ontologies/MGEDOntology.owl - * - * @return + * Defines the location of the ontology eg: MGED */ protected abstract String getOntologyUrl(); /** * Delegates the call as to load the model into memory or leave it on disk. Simply delegates to either * OntologyLoader.loadMemoryModel( url ); OR OntologyLoader.loadPersistentModel( url, spec ); - * - * @param url - * @return - * @throws IOException */ protected abstract OntModel loadModel(); - /** - * @param url - * @param m - * @throws IOException - */ - protected void loadTermsInNameSpace( String url, OntModel m ) { - Collection t = OntologyLoader.initialize( url, m ); - addTerms( t ); + @Override + public void index( boolean force ) { + Lock lock = rwLock.writeLock(); + try { + lock.lock(); + if ( !isInitialized ) { + log.warn( String.format( "Ontology %s is not initialized, cannot index it.", getOntologyName() ) ); + return; + } + index = OntologyIndexer.indexOntology( getOntologyName(), model, force ); + } finally { + lock.unlock(); + } } - /* + /** + * Initialize alternative IDs mapping. + *

* this add alternative id in 2 ways - * + *

* Example : - * - * http://purl.obolibrary.org/obo/HP_0000005 with alternative id : HP:0001453 - * - * by default way use in file 1- HP:0001453 -----> http://purl.obolibrary.org/obo/HP_0000005 - * - * trying to use the value uri 2- http://purl.obolibrary.org/obo/HP_0001453 -----> - * http://purl.obolibrary.org/obo/HP_0000005 + *

+ * HP_0000005 with alternative id : HP:0001453 + *

+ * by default way use in file 1- HP:0001453 -----> HP_0000005 + *

+ * trying HP_0001453ibrary.org/obo/HP_0001453 -----> + * HP_0000005 */ private void initSearchByAlternativeId() { - - // lets find the baseUrl, to change to valueUri - String randomUri = terms.values().iterator().next().getUri(); - String baseOntologyUri = randomUri.substring( 0, randomUri.lastIndexOf( "/" ) + 1 ); - + alternativeIDs = new HashMap<>(); // for all Ontology terms that exist in the tree - for ( OntologyTerm ontologyTerm : terms.values() ) { - + ExtendedIterator iterator = model.listClasses(); + while ( iterator.hasNext() ) { + OntClass ind = iterator.next(); + OntologyTerm ontologyTerm = new OntologyTermImpl( ind ); + // lets find the baseUri, to change to valueUri + String baseOntologyUri = ontologyTerm.getUri().substring( 0, ontologyTerm.getUri().lastIndexOf( "/" ) + 1 ); for ( String alternativeId : ontologyTerm.getAlternativeIds() ) { // first way - alternativeIDs.put( alternativeId, ontologyTerm ); - - String alternativeIdModified = alternativeId.replace( ':', '_' ); - + alternativeIDs.put( alternativeId, ontologyTerm.getUri() ); // second way - alternativeIDs.put( baseOntologyUri + alternativeIdModified, ontologyTerm ); + String alternativeIdModified = alternativeId.replace( ':', '_' ); + alternativeIDs.put( baseOntologyUri + alternativeIdModified, ontologyTerm.getUri() ); } } } + private OntologyTerm getTermInternal( String uri ) { + return termCache.computeIfAbsent( uri, u -> { + OntClass ontCls = model.getOntClass( u ); + // bnode + if ( ontCls.getURI() == null ) { + return null; + } + return new OntologyTermImpl( ontCls ); + } ); + } + + @Override + public void loadTermsInNameSpace( InputStream is, boolean forceIndex ) { + Lock lock = rwLock.writeLock(); + try { + lock.lock(); + this.isInitialized = false; + + if ( initializationThread != null && initializationThread.isAlive() ) { + log.warn( this.getOntologyName() + " initialization is already running, trying to cancel ..." ); + initializationThread.interrupt(); + // wait for the thread to die. + int maxWait = 10; + int wait = 0; + while ( initializationThread.isAlive() ) { + try { + initializationThread.join( 5000 ); + log.warn( "Waiting for auto-initialization to stop so manual initialization can begin ..." ); + } catch ( InterruptedException e ) { + Thread.currentThread().interrupt(); + log.warn( String.format( "Got interrupted while waiting for the initialization thread of %s to finish.", getOntologyName() ) ); + return; + } + ++wait; + if ( wait >= maxWait && !initializationThread.isAlive() ) { + throw new RuntimeException( String.format( "Got tired of waiting for %s's initialization thread.", getOntologyName() ) ); + } + } + } + + this.model = OntologyLoader.loadMemoryModel( is, this.getOntologyUrl() ); + this.termCache.clear(); + this.index = OntologyIndexer.getSubjectIndex( getOntologyName() ); + if ( index == null || forceIndex ) { + this.index = OntologyIndexer.indexOntology( getOntologyName(), model, true /* force */ ); + } + + isInitialized = true; + } finally { + lock.unlock(); + } + + log.info( this.getClass().getSimpleName() + " ready" ); + } } \ No newline at end of file diff --git a/src/ubic/basecode/ontology/providers/OntologyService.java b/src/ubic/basecode/ontology/providers/OntologyService.java new file mode 100644 index 00000000..f50f2405 --- /dev/null +++ b/src/ubic/basecode/ontology/providers/OntologyService.java @@ -0,0 +1,103 @@ +package ubic.basecode.ontology.providers; + +import ubic.basecode.ontology.model.OntologyIndividual; +import ubic.basecode.ontology.model.OntologyResource; +import ubic.basecode.ontology.model.OntologyTerm; +import ubic.basecode.ontology.search.OntologySearchException; + +import java.io.InputStream; +import java.util.Collection; +import java.util.Set; + +public interface OntologyService { + + /** + * Initialize this ontology service. + */ + void initialize( boolean forceLoad, boolean forceIndexing ); + + /** + * Looks for any OntologyIndividuals that match the given search string. + */ + Collection findIndividuals( String search ) throws OntologySearchException; + + /** + * Looks for any OntologyIndividuals or ontologyTerms that match the given search string + * + * @return results, or an empty collection if the results are empty OR the ontology is not available to be + * searched. + */ + Collection findResources( String searchString ) throws OntologySearchException; + + /** + * Looks for any ontologyTerms that match the given search string. Obsolete terms are filtered out. + */ + Collection findTerm( String search ) throws OntologySearchException; + + OntologyTerm findUsingAlternativeId( String alternativeId ); + + Set getAllURIs(); + + /** + * Looks through both Terms and Individuals for a OntologyResource that has a uri matching the uri given. If no + * OntologyTerm is found only then will ontologyIndividuals be searched. returns null if nothing is found. + */ + OntologyResource getResource( String uri ); + + /** + * Looks for a OntologyTerm that has the match in URI given + */ + OntologyTerm getTerm( String uri ); + + Collection getTermIndividuals( String uri ); + + boolean isEnabled(); + + /** + * Used for determining if the Ontology has finished loading into memory. Although calls like getParents, + * getChildren will still work (its much faster once the ontologies have been preloaded into memory.) + */ + boolean isOntologyLoaded(); + + /** + * Start the initialization thread. + *

+ * If the initialization thread is already running, this method does nothing. If the initialization thread + * previously completed, the ontology will be reinitialized. + * + * @param forceLoad Force loading of ontology, even if it is already loaded + * @param forceIndexing If forceLoad is also true, indexing will be performed. If you know the index is + * up to date, there's no need to do it again. Normally indexing is only done if there is no + * index, or if the ontology has changed since last loaded. + */ + void startInitializationThread( boolean forceLoad, boolean forceIndexing ); + + boolean isInitializationThreadAlive(); + + boolean isInitializationThreadCancelled(); + + void cancelInitializationThread(); + + /** + * Wait for the initialization thread to finish. + */ + void waitForInitializationThread() throws InterruptedException; + + /** + * Index the ontology for performing full-text searches. + * + * @see #findIndividuals(String) + * @see #findTerm(String) + * @see #findResources(String) + */ + void index( boolean force ); + + /** + * For testing! Overrides normal way of loading the ontology. This does not index the ontology unless 'force' is + * true (if there is an existing index, it will be used) + * + * @param is input stream from which the ontology model is loaded + * @param forceIndex initialize the index. Otherwise it will only be initialized if it doesn't exist. + */ + void loadTermsInNameSpace( InputStream is, boolean forceIndex ); +} diff --git a/test/data/uberon.owl.gz b/test/data/uberon.owl.gz new file mode 100644 index 00000000..34e4a6f7 Binary files /dev/null and b/test/data/uberon.owl.gz differ diff --git a/test/log4j2-test.xml b/test/log4j2-test.xml index d130a10c..b275c446 100644 --- a/test/log4j2-test.xml +++ b/test/log4j2-test.xml @@ -6,7 +6,7 @@ - + diff --git a/test/ubic/basecode/ontology/OntologyTermTest.java b/test/ubic/basecode/ontology/OntologyTermTest.java index cc891809..ed0fe4bf 100644 --- a/test/ubic/basecode/ontology/OntologyTermTest.java +++ b/test/ubic/basecode/ontology/OntologyTermTest.java @@ -1,36 +1,34 @@ /* * The baseCode project - * + * * Copyright (c) 2012 University of British Columbia - * + * * 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 ubic.basecode.ontology; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.InputStream; -import java.util.Collection; -import java.util.zip.GZIPInputStream; - import org.apache.commons.lang3.StringUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import ubic.basecode.ontology.model.OntologyTerm; import ubic.basecode.ontology.providers.CellLineOntologyService; import ubic.basecode.ontology.providers.DiseaseOntologyService; import ubic.basecode.ontology.providers.NIFSTDOntologyService; +import ubic.basecode.ontology.providers.UberonOntologyService; + +import java.io.InputStream; +import java.util.Collection; +import java.util.zip.GZIPInputStream; + +import static org.junit.Assert.*; /** * @author Paul @@ -82,7 +80,7 @@ public void testGetChildren() throws Exception { /** * FIXME this uses NIF, which we are no longer using actively - not a big deal since this just tests mechanics - * + * * @throws Exception */ @Test @@ -92,13 +90,11 @@ public void testGetChildrenHasProperPart() throws Exception { "/data/NIF-GrossAnatomy.small.owl.xml.gz" ) ); s.loadTermsInNameSpace( is, false ); - OntologyTerm t = s - .getTerm( "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_734" ); - + OntologyTerm t = s.getTerm( "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_734" ); assertNotNull( t ); Collection c = t.getChildren( true ); - assertEquals( 9, c.size() ); + assertEquals( 6, c.size() ); // Dorsal hypothalamic area [birnlex_777] // Lateral hypothalamic area [birnlex_4037] // Medial forebrain bundle [birnlex_908] @@ -108,36 +104,15 @@ public void testGetChildrenHasProperPart() throws Exception { // Anterior hypothalamic region [birnlex_1005] // Intermediate hypothalamic region [birnlex_1015] // Regional part of hypothalamus [birnlex_995] - boolean found = false; - for ( OntologyTerm o : c ) { - // System.err.println( o ); - if ( o.getUri().equals( - "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_898" ) ) { - found = true; - } - } - assertTrue( found ); + OntologyTerm t1 = s.getTerm( "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_898" ); + assertNotNull( t1 ); + assertTrue( c.contains( t1 ) ); Collection c2 = t.getChildren( false ); - assertEquals( 11, c2.size() ); - found = false; - for ( OntologyTerm o : c2 ) { - System.err.println( o ); - if ( o.getUri().equals( - "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_4037" ) ) { - found = true; - } - - // exercise other things. - log.info( "Annotations: " + StringUtils.join( o.getAnnotations(), "," ) ); - log.info( "Comment: " + o.getComment() ); - log.info( "Individuals: " + StringUtils.join( o.getIndividuals(), "," ) ); - log.info( "Individuals: " + StringUtils.join( o.getIndividuals( true ), "," ) ); - log.info( "Individuals: " + StringUtils.join( o.getIndividuals( false ), "," ) ); - // Log.info( "Restrictions: "+ StringUtils.join( o.getRestrictions(), "," ) ); - log.info( "AlternativeIDs: " + StringUtils.join( o.getAlternativeIds(), "," ) ); - } - assertTrue( found ); + assertEquals( 6, c2.size() ); + OntologyTerm t2 = s.getTerm( "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_4037" ); + assertNotNull( t2 ); + assertTrue( c.contains( t2 ) ); } @Test @@ -219,27 +194,16 @@ public void testGetParentsHasProperPart() throws Exception { // Diencephalon [birnlex_1503] x Collection parents2 = t.getParents( false ); - assertEquals( 12, parents2.size() ); + assertEquals( 5, parents2.size() ); // does not includes 'continuant' and 'independent continuant' or parents of those terms. - found = false; - for ( OntologyTerm p : parents2 ) { - // System.err.println( p + " " + p.getUri() ); - - if ( p.getUri().equals( - "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_1503" ) ) { - found = true; - } - - assertTrue( !p.getUri().equals( "http://www.ifomis.org/bfo/1.1/snap#Continuant" ) ); - - } - assertTrue( found ); + // assertTrue( parents2.contains( s.getTerm( "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl#birnlex_1503" ) ) ); + assertFalse( parents2.contains( s.getResource( "http://www.ifomis.org/bfo/1.1/snap#Continuant" ) ) ); } - + @Test public void testRejectNonEnglish() throws Exception { - CellLineOntologyService s = new CellLineOntologyService(); + CellLineOntologyService s = new CellLineOntologyService(); InputStream is = new GZIPInputStream( this.getClass().getResourceAsStream( "/data/clo_merged.sample.owl.xml.gz" ) ); s.loadTermsInNameSpace( is, false ); @@ -247,4 +211,41 @@ public void testRejectNonEnglish() throws Exception { assertEquals( "immortal larynx-derived cell line cell", t.getLabel() ); } + + @Test + public void testGetParentsHasPart() throws Exception { + UberonOntologyService s = new UberonOntologyService(); + try ( InputStream is = new GZIPInputStream( getClass().getResourceAsStream( "/data/uberon.owl.gz" ) ) ) { + s.loadTermsInNameSpace( is, false ); + } + OntologyTerm t = s.getTerm( "http://purl.obolibrary.org/obo/UBERON_0000955" ); + assertNotNull( t ); + Collection parents = t.getParents( true ); + assertEquals( 3, parents.size() ); + // does not contain itself + assertFalse( parents.contains( t ) ); + // via subclass + assertTrue( parents.contains( s.getTerm( "http://purl.obolibrary.org/obo/UBERON_0004121" ) ) ); + assertTrue( parents.contains( s.getTerm( "http://purl.obolibrary.org/obo/UBERON_0000062" ) ) ); + // via part of, central nervous system + assertTrue( parents.contains( s.getTerm( "http://purl.obolibrary.org/obo/UBERON_0001017" ) ) ); + } + + @Test + public void testGetChildrenHasPart() throws Exception { + UberonOntologyService s = new UberonOntologyService(); + try ( InputStream is = new GZIPInputStream( getClass().getResourceAsStream( "/data/uberon.owl.gz" ) ) ) { + s.loadTermsInNameSpace( is, false ); + } + OntologyTerm t = s.getTerm( "http://purl.obolibrary.org/obo/UBERON_0000955" ); + assertNotNull( t ); + Collection children = t.getChildren( false ); + assertEquals( 1496, children.size() ); + // via subclass of, insect adult brain + assertTrue( children.contains( s.getTerm( "http://purl.obolibrary.org/obo/UBERON_6003624" ) ) ); + // via part of, nucleus of brain + assertTrue( children.contains( s.getTerm( "http://purl.obolibrary.org/obo/UBERON_0002308" ) ) ); + // does not contain owl:Nothing + assertFalse( children.contains( s.getTerm( "http://www.w3.org/2002/07/owl#Nothing" ) ) ); + } } diff --git a/test/ubic/basecode/ontology/providers/AbstractOntologyServiceTest.java b/test/ubic/basecode/ontology/providers/AbstractOntologyServiceTest.java index 50a0aea9..ef8f91ad 100644 --- a/test/ubic/basecode/ontology/providers/AbstractOntologyServiceTest.java +++ b/test/ubic/basecode/ontology/providers/AbstractOntologyServiceTest.java @@ -1,8 +1,8 @@ /* * The baseCode project - * + * * Copyright (c) 2017 University of British Columbia - * + * * 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 @@ -19,22 +19,22 @@ package ubic.basecode.ontology.providers; -import static org.junit.Assert.assertTrue; - import java.io.File; import java.net.URL; import java.util.Collection; import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import ubic.basecode.ontology.OntologyLoader; import ubic.basecode.ontology.model.OntologyTerm; import ubic.basecode.util.Configuration; +import static org.junit.Assert.*; + /** - * * @author mjacobson */ public class AbstractOntologyServiceTest { @@ -54,6 +54,7 @@ public static void tearDown() throws Exception { } @Test + @Ignore("This test was always broken, but the failure was obscured in a thread.") public void testCacheOntologyToDisk() throws Exception { String name = "fooTEST1234"; @@ -104,19 +105,22 @@ public void testReindexOnInitialize() throws Exception { } - private GenericOntologyService createService( String name, String resourceURL, boolean cache ) throws Exception { - - GenericOntologyService s = new GenericOntologyService( name, resourceURL, cache ); - + @Test + public void testInitializeInBackgroundThread() throws InterruptedException { + URL resource = this.getClass().getResource( dataResource ); + assertNotNull( resource ); + GenericOntologyService s = new GenericOntologyService( "foo", resource.toString(), false ); s.startInitializationThread( true, false ); - int i = 0; - while ( s.isInitializationThreadAlive() && !s.isOntologyLoaded() ) { - Thread.sleep( 1000 ); - if ( ++i > 100 ) { - break; - } - } + assertTrue( s.isInitializationThreadAlive() ); + s.cancelInitializationThread(); + assertTrue( s.isInitializationThreadCancelled() ); + s.waitForInitializationThread(); + assertFalse( s.isInitializationThreadAlive() ); + } + private GenericOntologyService createService( String name, String resourceURL, boolean cache ) throws Exception { + GenericOntologyService s = new GenericOntologyService( name, resourceURL, cache ); + s.initialize( true, false ); return s; } } diff --git a/test/ubic/basecode/ontology/providers/ObiServiceTest.java b/test/ubic/basecode/ontology/providers/ObiServiceTest.java index 54518e10..5eaa2c4e 100644 --- a/test/ubic/basecode/ontology/providers/ObiServiceTest.java +++ b/test/ubic/basecode/ontology/providers/ObiServiceTest.java @@ -1,13 +1,13 @@ /* * The baseCode project - * + * * Copyright (c) 2012 University of British Columbia - * + * * 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. @@ -37,18 +37,7 @@ public class ObiServiceTest { @Test public void testLoadAndSearch() throws Exception { ObiService m = new ObiService(); - m.startInitializationThread( true, false ); - m.startInitializationThread( true, false ); - m.startInitializationThread( true, false ); - int i = 0; - while ( !m.isOntologyLoaded() ) { - - Thread.sleep( 3000 ); - i++; - log.info( "Waiting for OBI to load ... " + i ); - - if ( i > 20 ) fail( "OBI Ontology didn't load in time" ); - } + m.initialize( true, false ); assertTrue( m.isOntologyLoaded() ); diff --git a/test/ubic/basecode/ontology/search/OntologySearchTest.java b/test/ubic/basecode/ontology/search/OntologySearchTest.java index f8a7b1b7..1fb1caf5 100644 --- a/test/ubic/basecode/ontology/search/OntologySearchTest.java +++ b/test/ubic/basecode/ontology/search/OntologySearchTest.java @@ -14,36 +14,31 @@ */ package ubic.basecode.ontology.search; -import static org.junit.Assert.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.shared.JenaException; +import org.junit.Test; +import ubic.basecode.ontology.OntologyLoader; +import ubic.basecode.ontology.model.OntologyTerm; import java.io.InputStream; import java.util.Collection; import java.util.zip.GZIPInputStream; -import com.hp.hpl.jena.shared.JenaException; -import org.junit.Test; - -import com.hp.hpl.jena.ontology.OntModel; -import com.hp.hpl.jena.ontology.OntModelSpec; - -import ubic.basecode.ontology.OntologyLoader; -import ubic.basecode.ontology.model.OntologyTerm; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; /** * Most of these tests were moved over from Gemma. * * @author Paul - * */ public class OntologySearchTest { @Test public final void testIndexing() throws Exception { InputStream is = new GZIPInputStream( this.getClass().getResourceAsStream( "/data/mged.owl.gz" ) ); - OntModel model = OntologyLoader.loadMemoryModel( is, "owl-test", OntModelSpec.OWL_MEM_TRANS_INF ); + OntModel model = OntologyLoader.loadMemoryModel( is, "owl-test" ); SearchIndex index = OntologyIndexer.indexOntology( "MGEDTEST", model, true ); @@ -68,7 +63,7 @@ public final void testIndexing() throws Exception { public final void testOmitBadPredicates() throws Exception { InputStream is = this.getClass().getResourceAsStream( "/data/niforgantest.owl.xml" ); - OntModel model = OntologyLoader.loadMemoryModel( is, "NIFTEST", OntModelSpec.OWL_MEM_TRANS_INF ); + OntModel model = OntologyLoader.loadMemoryModel( is, "NIFTEST" ); is.close(); SearchIndex index = OntologyIndexer.indexOntology( "NIFTEST", model, true ); @@ -105,7 +100,7 @@ public final void testOmitBadPredicates() throws Exception { @Test public final void testOmitBadPredicates2() throws Exception { InputStream is = this.getClass().getResourceAsStream( "/data/eftest.owl.xml" ); - OntModel model = OntologyLoader.loadMemoryModel( is, "EFTEST", OntModelSpec.OWL_MEM_TRANS_INF ); + OntModel model = OntologyLoader.loadMemoryModel( is, "EFTEST" ); is.close(); SearchIndex index = OntologyIndexer.indexOntology( "EFTEST", model, true ); @@ -128,7 +123,7 @@ public final void testOmitBadPredicates2() throws Exception { @Test public final void testOmitDefinitions() throws Exception { InputStream is = this.getClass().getResourceAsStream( "/data/dotest.owl.xml" ); - OntModel model = OntologyLoader.loadMemoryModel( is, "DO_TEST", OntModelSpec.OWL_MEM_TRANS_INF ); + OntModel model = OntologyLoader.loadMemoryModel( is, "DO_TEST" ); is.close(); SearchIndex index = OntologyIndexer.indexOntology( "DO_TEST", model, true ); @@ -150,7 +145,7 @@ public final void testOmitDefinitions() throws Exception { @Test public final void testOmitDefinitions2() throws Exception { InputStream is = this.getClass().getResourceAsStream( "/data/nif.organism.test.owl.xml" ); - OntModel model = OntologyLoader.loadMemoryModel( is, "NIFORG_TEST", OntModelSpec.OWL_MEM_TRANS_INF ); + OntModel model = OntologyLoader.loadMemoryModel( is, "NIFORG_TEST" ); is.close(); SearchIndex index = OntologyIndexer.indexOntology( "NIFORG_TEST", model, true ); @@ -190,7 +185,7 @@ public final void testOmitDefinitions2() throws Exception { @Test public final void testOmitDefinitions3() throws Exception { InputStream is = this.getClass().getResourceAsStream( "/data/obi.test.owl.xml" ); - OntModel model = OntologyLoader.loadMemoryModel( is, "OBI_TEST", OntModelSpec.OWL_MEM_TRANS_INF ); + OntModel model = OntologyLoader.loadMemoryModel( is, "OBI_TEST" ); SearchIndex index = OntologyIndexer.indexOntology( "OBI_TEST", model, true ); @@ -213,7 +208,7 @@ public final void testOmitDefinitions3() throws Exception { public final void testOmitDefinitions4() throws Exception { InputStream is = new GZIPInputStream( this.getClass().getResourceAsStream( "/data/NIF-GrossAnatomy.owl.gz" ) ); - OntModel model = OntologyLoader.loadMemoryModel( is, "NIFAN_TEST2", OntModelSpec.OWL_MEM_TRANS_INF ); + OntModel model = OntologyLoader.loadMemoryModel( is, "NIFAN_TEST2" ); is.close(); SearchIndex index = OntologyIndexer.indexOntology( "NIFAN_TEST2", model, true ); @@ -238,7 +233,7 @@ public final void testOmitDefinitions4() throws Exception { @Test public final void testPersistence() throws Exception { InputStream is = new GZIPInputStream( this.getClass().getResourceAsStream( "/data/mged.owl.gz" ) ); - OntModel model = OntologyLoader.loadMemoryModel( is, "owl-test", OntModelSpec.OWL_MEM_TRANS_INF ); + OntModel model = OntologyLoader.loadMemoryModel( is, "owl-test" ); SearchIndex index = OntologyIndexer.indexOntology( "MGEDTEST", model, false ); index.close();