package jalview.io.gff; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import org.biojava.nbio.ontology.Ontology; import org.biojava.nbio.ontology.Term; import org.biojava.nbio.ontology.Term.Impl; import org.biojava.nbio.ontology.Triple; import org.biojava.nbio.ontology.io.OboParser; /** * A wrapper class that parses the Sequence Ontology and exposes useful access * methods. This version uses the BioJava parser. */ public class SequenceOntology { private static SequenceOntology instance = new SequenceOntology(); private Ontology ontology; private Term isA; /* * lookup of terms by user readable name (NB not guaranteed unique) */ private Map termsByDescription; /* * Map where key is a Term and value is a (possibly empty) list of * all Terms to which the key has a direct 'isA' relationship */ private Map> termIsA; public static SequenceOntology getInstance() { return instance; } /** * Private constructor to enforce use of singleton. Parses and caches the SO * OBO data file. */ private SequenceOntology() { termsByDescription = new HashMap(); termIsA = new HashMap>(); OboParser parser = new OboParser(); InputStream inStream = null; try { inStream = new FileInputStream( "/Users/gmcarstairs/Documents/ontologies/so-xp-simple.obo"); BufferedReader oboFile = new BufferedReader(new InputStreamReader( inStream)); ontology = parser.parseOBO(oboFile, "SO", "the SO ontology"); isA = ontology.getTerm("is_a"); storeTermNames(); } catch (Exception e) { e.printStackTrace(); } finally { if (inStream != null) { try { inStream.close(); } catch (IOException e) { // ignore } } } } protected void storeTermNames() { for (Term term : ontology.getTerms()) { if (term instanceof Impl) { String description = term.getDescription(); if (description != null) { // System.out.println(term.getName() + "=" + term.getDescription()); Term replaced = termsByDescription.put(description, term); if (replaced != null) { System.err.println("Warning: " + term.getName() + " has replaced " + replaced.getName() + " for lookup of description " + description); } } } } } /** * Test whether the given Sequence Ontology term is nucleotide_match (either * directly or via is_a relationship) * * @param soTerm * @return */ public boolean isNucleotideMatch(String soTerm) { return isA(soTerm, "nucleotide_match"); } /** * Test whether the given Sequence Ontology term is protein_match (either * directly or via is_a relationship) * * @param soTerm * @return */ public boolean isProteinMatch(String soTerm) { return isA(soTerm, "protein_match"); } public boolean isPolypeptide(String soTerm) { return isA(soTerm, "polypeptide"); } /** * Returns true if the given term has a (direct or indirect) 'isA' * relationship with the parent * * @param child * @param parent * @return */ public boolean isA(String child, String parent) { Term childTerm = getTerm(child); Term parentTerm = getTerm(parent); return termIsA(childTerm, parentTerm); } /** * Returns true if the childTerm 'isA' parentTerm (directly or indirectly). * * @param childTerm * @param parentTerm * @return */ protected synchronized boolean termIsA(Term childTerm, Term parentTerm) { /* * null child term arises from a misspelled SO description */ if (childTerm == null || parentTerm == null) { return false; } /* * recursive search endpoint: */ if (childTerm == parentTerm) { return true; } /* * lazy initialisation - find all of a term's parents the first * time this is called, and save them in a map. */ if (!termIsA.containsKey(childTerm)) { findParents(childTerm); } List parents = termIsA.get(childTerm); for (Term parent : parents) { if (termIsA(parent, parentTerm)) { return true; } } return false; } /** * Finds all the 'isA' parents of the childTerm and stores them as a (possibly * empty) list. * * @param childTerm */ protected synchronized void findParents(Term childTerm) { List result = new ArrayList(); for (Triple triple : ontology.getTriples(childTerm, null, isA)) { Term parent = triple.getObject(); result.add(parent); /* * and search for the parent's parents recursively */ findParents(parent); } termIsA.put(childTerm, result); } /** * Returns the Term for a given name (e.g. "SO:0000735") or description (e.g. * "sequence_location"), or null if not found. * * @param child * @return */ protected Term getTerm(String nameOrDescription) { Term t = termsByDescription.get(nameOrDescription); if (t == null) { try { t = ontology.getTerm(nameOrDescription); } catch (NoSuchElementException e) { // not found } } return t; } }