ubic.gemma.ontology.providers.GeneOntologyServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for ubic.gemma.ontology.providers.GeneOntologyServiceImpl.java

Source

/*
    
 * 
 * Copyright (c) 2007 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.gemma.ontology.providers;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang.time.StopWatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ubic.basecode.ontology.OntologyLoader;
import ubic.basecode.ontology.model.AnnotationProperty;
import ubic.basecode.ontology.model.OntologyClassRestriction;
import ubic.basecode.ontology.model.OntologyResource;
import ubic.basecode.ontology.model.OntologyTerm;
import ubic.basecode.ontology.search.OntologyIndexer;
import ubic.basecode.ontology.search.OntologySearch;
import ubic.gemma.genome.gene.service.GeneService;
import ubic.gemma.model.association.Gene2GOAssociationService;
import ubic.gemma.model.common.description.Characteristic;
import ubic.gemma.model.common.description.VocabCharacteristic;
import ubic.gemma.model.genome.Gene;
import ubic.gemma.model.genome.Taxon;
import ubic.gemma.util.ConfigUtils;

import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.larq.IndexLARQ;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;

/**
 * Holds a complete copy of the GeneOntology. This gets loaded on startup.
 * 
 * @author pavlidis
 * @version $Id: GeneOntologyServiceImpl.java,v 1.10 2012/07/06 05:38:44 paul Exp $
 */
@Component
public class GeneOntologyServiceImpl implements GeneOntologyService {

    public static enum GOAspect {
        BIOLOGICAL_PROCESS, CELLULAR_COMPONENT, MOLECULAR_FUNCTION
    }

    private static final String ALL_ROOT = BASE_GO_URI + "ALL";

    private final static String BP_URL = "http://www.berkeleybop.org/ontologies/obo-all/biological_process/biological_process.owl";

    private final static String CC_URL = "http://www.berkeleybop.org/ontologies/obo-all/cellular_component/cellular_component.owl";

    private static boolean enabled = true;

    private final static boolean LOAD_BY_DEFAULT = true;

    private static final String LOAD_GENE_ONTOLOGY_OPTION = "load.geneOntology";

    private static Log log = LogFactory.getLog(GeneOntologyServiceImpl.class.getName());

    private final static String MF_URL = "http://www.berkeleybop.org/ontologies/obo-all/molecular_function/molecular_function.owl";

    private static final String PART_OF_URI = "http://purl.org/obo/owl/OBO_REL#part_of";
    private static final AtomicBoolean ready = new AtomicBoolean(false);
    private static final AtomicBoolean running = new AtomicBoolean(false);

    private static Map<String, GOAspect> term2Aspect = new HashMap<String, GOAspect>();

    // map of uris to terms
    private static Map<String, OntologyTerm> uri2Term = new HashMap<String, OntologyTerm>();

    /**
     * @param term
     * @return Usual formatted GO id, e.g., GO:0039392
     */
    public static String asRegularGoId(Characteristic term) {
        String uri = term.getValue();
        return asRegularGoId(uri);
    }

    /**
     * @param term
     * @return Usual formatted GO id, e.g., GO:0039392
     */
    public static String asRegularGoId(OntologyTerm term) {
        if (term == null)
            return null;
        String uri = term.getUri();
        return asRegularGoId(uri);
    }

    public static String asRegularGoId(String uri) {
        return uri.replaceAll(".*?#", "").replace("_", ":");
    }

    /**
     * @param goId
     * @return
     */
    public static GOAspect getTermAspect(String goId) {
        OntologyTerm term = getTermForId(goId);
        if (term == null)
            return null;
        return getTermAspect(term);
    }

    /**
     * @param goId
     * @return
     */
    public static GOAspect getTermAspect(VocabCharacteristic goId) {
        String string = asRegularGoId(goId);
        return getTermAspect(string);
    }

    /**
     * @param goId e.g. GO:0001312
     * @return null if not found
     */
    public static OntologyTerm getTermForId(String goId) {
        if (uri2Term == null)
            return null;
        return uri2Term.get(toUri(goId));
    }

    /*
     * @param goURI e.g. GO:0001312 @return null if not found
     */
    public static OntologyTerm getTermForURI(String uri) {
        if (uri2Term == null)
            return null;
        return uri2Term.get(uri);
    }

    public static boolean isEnabled() {
        return enabled;
    }

    /**
     * @param term
     * @return
     */
    private static GOAspect getTermAspect(OntologyTerm term) {
        assert term != null;
        String goid = term.getTerm();
        if (term2Aspect.containsKey(goid)) {
            return term2Aspect.get(goid);
        }

        String nameSpace = null;
        for (AnnotationProperty annot : term.getAnnotations()) {
            if (annot.getProperty().equals("hasOBONamespace")) {
                nameSpace = annot.getContents();
                break;
            }
        }

        if (nameSpace == null) {
            throw new IllegalArgumentException("Unknown GO id " + goid);
        }

        GOAspect aspect = GOAspect.valueOf(nameSpace.toUpperCase());
        term2Aspect.put(goid, aspect);

        return aspect;
    }

    /**
     * Turn an id like GO:0038128 into a URI.
     * 
     * @param goId
     * @return
     */
    private static String toUri(String goId) {
        String uriTerm = goId.replace(":", "_");
        return BASE_GO_URI + uriTerm;
    }

    /**
     * Cache of go term -> child terms
     */
    private Map<String, Collection<OntologyTerm>> childrenCache = Collections
            .synchronizedMap(new HashMap<String, Collection<OntologyTerm>>());

    @Autowired
    private Gene2GOAssociationService gene2GOAssociationService;

    @Autowired
    private GeneService geneService;

    /**
     * Cache of gene -> go terms.
     */
    private Map<Gene, Collection<OntologyTerm>> goTerms = new HashMap<Gene, Collection<OntologyTerm>>();

    private Collection<IndexLARQ> indices = new HashSet<IndexLARQ>();

    private OntModel model;

    /**
     * Cache of go term -> parent terms
     */
    private Map<String, Collection<OntologyTerm>> parentsCache = Collections
            .synchronizedMap(new HashMap<String, Collection<OntologyTerm>>());

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() {
        this.init(false);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#calculateGoTermOverlap(ubic.gemma.model.genome.Gene,
     * java.util.Collection)
     */
    @Override
    public Map<Long, Collection<OntologyTerm>> calculateGoTermOverlap(Gene queryGene, Collection<Long> geneIds) {

        Map<Long, Collection<OntologyTerm>> overlap = new HashMap<Long, Collection<OntologyTerm>>();
        if (queryGene == null)
            return null;
        if (geneIds.size() == 0)
            return overlap;

        Collection<OntologyTerm> queryGeneTerms = getGOTerms(queryGene);

        overlap.put(queryGene.getId(), queryGeneTerms); // include the query gene in the list. Clearly 100% overlap
        // with itself!

        Collection<Gene> genes = this.geneService.loadMultiple(geneIds);

        for (Object obj : genes) {
            Gene gene = (Gene) obj;
            if (queryGeneTerms.isEmpty()) {
                overlap.put(gene.getId(), new HashSet<OntologyTerm>());
                continue;
            }

            Collection<OntologyTerm> comparisonOntos = getGOTerms(gene);

            if (comparisonOntos == null || comparisonOntos.isEmpty()) {
                overlap.put(gene.getId(), new HashSet<OntologyTerm>());
                continue;
            }

            overlap.put(gene.getId(), computeOverlap(queryGeneTerms, comparisonOntos));
        }

        return overlap;
    }

    @Override
    public Map<Long, Collection<OntologyTerm>> calculateGoTermOverlap(Long queryGene, Collection<Long> geneIds) {
        Map<Long, Collection<OntologyTerm>> overlap = new HashMap<Long, Collection<OntologyTerm>>();
        if (queryGene == null)
            return null;
        if (geneIds.size() == 0)
            return overlap;

        Collection<OntologyTerm> queryGeneTerms = getGOTerms(queryGene);

        overlap.put(queryGene, queryGeneTerms); // include the query gene in the list. Clearly 100% overlap
        // with itself!

        Collection<Gene> genes = this.geneService.loadMultiple(geneIds);

        for (Object obj : genes) {
            Gene gene = (Gene) obj;
            if (queryGeneTerms.isEmpty()) {
                overlap.put(gene.getId(), new HashSet<OntologyTerm>());
                continue;
            }

            Collection<OntologyTerm> comparisonOntos = getGOTerms(gene);

            if (comparisonOntos == null || comparisonOntos.isEmpty()) {
                overlap.put(gene.getId(), new HashSet<OntologyTerm>());
                continue;
            }

            overlap.put(gene.getId(), computeOverlap(queryGeneTerms, comparisonOntos));
        }

        return overlap;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#calculateGoTermOverlap(ubic.gemma.model.genome.Gene,
     * ubic.gemma.model.genome.Gene)
     */
    @Override
    public Collection<OntologyTerm> calculateGoTermOverlap(Gene queryGene1, Gene queryGene2) {

        if (queryGene1 == null || queryGene2 == null)
            return null;

        Collection<OntologyTerm> queryGeneTerms1 = getGOTerms(queryGene1);
        Collection<OntologyTerm> queryGeneTerms2 = getGOTerms(queryGene2);

        return computeOverlap(queryGeneTerms1, queryGeneTerms2);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#computeOverlap(java.util.Collection, java.util.Collection)
     */
    @Override
    public Collection<OntologyTerm> computeOverlap(Collection<OntologyTerm> masterOntos,
            Collection<OntologyTerm> comparisonOntos) {
        Collection<OntologyTerm> overlapTerms = new HashSet<OntologyTerm>(masterOntos);
        overlapTerms.retainAll(comparisonOntos);

        return overlapTerms;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#findTerm(java.lang.String)
     */
    @Override
    public Collection<OntologyTerm> findTerm(String queryString) {

        if (!isReady())
            return new HashSet<OntologyTerm>();

        if (log.isDebugEnabled())
            log.debug("Searching Gene Ontology for '" + queryString + "'");

        // make sure we are all-inclusive
        queryString = queryString.trim();
        queryString = queryString.replaceAll("\\s+", " AND ");

        Collection<OntologyResource> rawMatches = new HashSet<OntologyResource>();
        for (IndexLARQ index : this.indices) {
            rawMatches.addAll(OntologySearch.matchIndividuals(model, index, queryString));
        }

        /*
         * Required to make sure the descriptions are filled in.
         */
        Collection<OntologyTerm> matches = new HashSet<OntologyTerm>();
        for (OntologyResource r : rawMatches) {
            if (r.getUri() == null)
                continue;
            OntologyTerm termForURI = GeneOntologyServiceImpl.getTermForURI(r.getUri());
            matches.add(termForURI);
        }
        return matches;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getAllChildren(ubic.basecode.ontology.model.OntologyTerm)
     */
    @Override
    public Collection<OntologyTerm> getAllChildren(OntologyTerm entry) {
        return getAllChildren(entry, false);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getAllChildren(ubic.basecode.ontology.model.OntologyTerm,
     * boolean)
     */
    @Override
    public Collection<OntologyTerm> getAllChildren(OntologyTerm entry, boolean includePartOf) {
        return getDescendants(entry, includePartOf);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getAllGOTermIds()
     */
    @Override
    public Collection<String> getAllGOTermIds() {
        Collection<String> goTermIds = uri2Term.keySet();
        return goTermIds;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getAllParents(java.util.Collection)
     */
    @Override
    public Collection<OntologyTerm> getAllParents(Collection<OntologyTerm> entries) {
        return getAllParents(entries, false);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getAllParents(java.util.Collection, boolean)
     */
    @Override
    public Collection<OntologyTerm> getAllParents(Collection<OntologyTerm> entries, boolean includePartOf) {
        if (entries == null)
            return null;
        Collection<OntologyTerm> result = new HashSet<OntologyTerm>();
        for (OntologyTerm entry : entries) {
            result.addAll(getAncestors(entry, includePartOf));
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getAllParents(ubic.basecode.ontology.model.OntologyTerm)
     */
    @Override
    public Collection<OntologyTerm> getAllParents(OntologyTerm entry) {
        return getAllParents(entry, true);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getAllParents(ubic.basecode.ontology.model.OntologyTerm,
     * boolean)
     */
    @Override
    public Collection<OntologyTerm> getAllParents(OntologyTerm entry, boolean includePartOf) {
        if (entry == null)
            return new HashSet<OntologyTerm>();
        return getAncestors(entry, includePartOf);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getChildren(ubic.basecode.ontology.model.OntologyTerm)
     */

    @Override
    public Collection<OntologyTerm> getChildren(OntologyTerm entry) {
        return getChildren(entry, false);

    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getChildren(ubic.basecode.ontology.model.OntologyTerm,
     * boolean)
     */
    @Override
    public Collection<OntologyTerm> getChildren(OntologyTerm entry, boolean includePartOf) {
        if (entry == null)
            return null;
        if (log.isDebugEnabled())
            log.debug("Getting children of " + entry);
        Collection<OntologyTerm> terms = entry.getChildren(true);

        if (includePartOf)
            terms.addAll(getPartsOf(entry));

        return terms;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getGenes(java.lang.String, ubic.gemma.model.genome.Taxon)
     */
    @Override
    public Collection<Gene> getGenes(String goId, Taxon taxon) {
        OntologyTerm t = getTermForId(goId);
        if (t == null)
            return null;
        Collection<OntologyTerm> terms = getAllChildren(t);
        Collection<Gene> results = new HashSet<Gene>(this.gene2GOAssociationService.findByGOTerm(goId, taxon));

        for (OntologyTerm term : terms) {
            results.addAll(this.gene2GOAssociationService.findByGOTerm(asRegularGoId(term), taxon));
        }
        return results;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getGOTerms(ubic.gemma.model.genome.Gene)
     */
    @Override
    public Collection<OntologyTerm> getGOTerms(Gene gene) {
        return getGOTerms(gene, true, null);
    }

    @Override
    public Collection<OntologyTerm> getGOTerms(Long geneId) {
        return getGOTerms(geneId, true, null);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getGOTerms(ubic.gemma.model.genome.Gene, boolean)
     */
    @Override
    public Collection<OntologyTerm> getGOTerms(Gene gene, boolean includePartOf) {
        return getGOTerms(gene, includePartOf, null);
    }

    /**
     * FIXME it might be better to avoid the fetch.
     * 
     * @param gene
     * @param includePartOf
     * @param goAspect
     * @return
     */
    public Collection<OntologyTerm> getGOTerms(Long gene, boolean includePartOf, GOAspect goAspect) {
        return this.getGOTerms(geneService.load(gene), includePartOf, goAspect);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getGOTerms(ubic.gemma.model.genome.Gene, boolean,
     * ubic.gemma.ontology.providers.GeneOntologyServiceImpl.GOAspect)
     */
    @Override
    public Collection<OntologyTerm> getGOTerms(Gene gene, boolean includePartOf, GOAspect goAspect) {
        Collection<OntologyTerm> cachedTerms = goTerms.get(gene);
        if (log.isTraceEnabled() && cachedTerms != null) {
            logIds("found cached GO terms for " + gene.getOfficialSymbol(), goTerms.get(gene));
        }

        if (cachedTerms == null) {
            Collection<OntologyTerm> allGOTermSet = new HashSet<OntologyTerm>();

            Collection<VocabCharacteristic> annotations = gene2GOAssociationService.findByGene(gene);
            for (VocabCharacteristic c : annotations) {
                if (!uri2Term.containsKey(c.getValueUri())) {
                    log.warn("Term " + c.getValueUri() + " not found in term list cant add to results");
                    continue;
                }
                allGOTermSet.add(uri2Term.get(c.getValueUri()));
            }

            allGOTermSet.addAll(getAllParents(allGOTermSet, includePartOf));

            cachedTerms = Collections.unmodifiableCollection(allGOTermSet);
            if (log.isTraceEnabled())
                logIds("caching GO terms for " + gene.getOfficialSymbol(), allGOTermSet);
            goTerms.put(gene, cachedTerms);
        }

        if (goAspect != null) {

            Collection<OntologyTerm> finalTerms = new HashSet<OntologyTerm>();

            for (OntologyTerm ontologyTerm : cachedTerms) {
                if (getTermAspect(ontologyTerm).equals(goAspect)) {
                    finalTerms.add(ontologyTerm);
                }
            }

            return finalTerms;
        }

        return cachedTerms;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getParents(ubic.basecode.ontology.model.OntologyTerm)
     */
    @Override
    public Collection<OntologyTerm> getParents(OntologyTerm entry) {
        return getParents(entry, false);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getParents(ubic.basecode.ontology.model.OntologyTerm,
     * boolean)
     */
    @Override
    public Collection<OntologyTerm> getParents(OntologyTerm entry, boolean includePartOf) {
        Collection<OntologyTerm> parents = entry.getParents(true);
        Collection<OntologyTerm> results = new HashSet<OntologyTerm>();
        for (OntologyTerm term : parents) {
            // The isRoot() returns true for the MolecularFunction, BiologicalProcess, CellularComponent
            if (term.isRoot())
                continue;
            if (term.getUri().equalsIgnoreCase(ALL_ROOT))
                continue;

            if (term instanceof OntologyClassRestriction) {
                // log.info( "Skipping " + term );
                // OntologyProperty restrictionOn = ( ( OntologyClassRestriction ) term ).getRestrictionOn();
                // if ( restrictionOn.getLabel().equals( "part_of" ) ) {
                // OntologyTerm restrictedTo = ( ( OntologyClassRestriction ) term ).getRestrictedTo();
                // results.add( restrictedTo );
                // }
            } else {
                // log.info( "Adding " + term );
                results.add(term);
            }
        }

        if (includePartOf)
            results.addAll(getIsPartOf(entry));

        return results;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getTermDefinition(java.lang.String)
     */
    @Override
    public String getTermDefinition(String goId) {
        OntologyTerm t = getTermForId(goId);
        assert t != null;
        Collection<AnnotationProperty> annotations = t.getAnnotations();
        for (AnnotationProperty annot : annotations) {
            log.info(annot.getProperty());
            if (annot.getProperty().equals("hasDefinition")) {
                return annot.getContents();
            }
        }
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#getTermName(java.lang.String)
     */
    @Override
    public String getTermName(String goId) {

        OntologyTerm t = getTermForId(goId);
        if (t == null)
            return "[Not available]"; // not ready yet?
        return t.getTerm();
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#init(boolean)
     */
    @Override
    public synchronized void init(boolean force) {

        if (running.get()) {
            log.warn("Gene Ontology initialization is already running");
            return;
        }

        boolean loadOntology = ConfigUtils.getBoolean(LOAD_GENE_ONTOLOGY_OPTION, LOAD_BY_DEFAULT);

        if (!force && !loadOntology) {
            log.info("Loading Gene Ontology is disabled (force=" + force + ", " + LOAD_GENE_ONTOLOGY_OPTION + "="
                    + loadOntology + ")");
            enabled = false;
            return;
        }

        initializeGeneOntology();
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#isAChildOf(ubic.basecode.ontology.model.OntologyTerm,
     * ubic.basecode.ontology.model.OntologyTerm)
     */
    @Override
    public Boolean isAChildOf(OntologyTerm parent, OntologyTerm potentialChild) {
        return isAParentOf(potentialChild, parent);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#isAParentOf(ubic.basecode.ontology.model.OntologyTerm,
     * ubic.basecode.ontology.model.OntologyTerm)
     */
    @Override
    public Boolean isAParentOf(OntologyTerm child, OntologyTerm potentialParent) {
        if (potentialParent.isRoot())
            return true; // well....
        Collection<OntologyTerm> parents = getAllParents(child);
        return parents.contains(potentialParent);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#isAValidGOId(java.lang.String)
     */
    @Override
    public Boolean isAValidGOId(String goId) {
        if (!this.isReady()) {
            throw new UnsupportedOperationException("Gene ontology isn't ready so cannot check validity of IDs");
        }
        if (uri2Term.containsKey(toUri(goId)))
            return true;
        return uri2Term.containsKey(toUri(goId.replaceFirst("_", ":")));
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * ubic.gemma.ontology.providers.GeneOntologyService#isBiologicalProcess(ubic.basecode.ontology.model.OntologyTerm)
     */
    @Override
    public boolean isBiologicalProcess(OntologyTerm term) {

        GOAspect nameSpace = getTermAspect(term);
        if (nameSpace == null) {
            log.warn("No namespace for " + term + ", assuming not Biological Process");
            return false;
        }

        return nameSpace.equals(GOAspect.BIOLOGICAL_PROCESS);
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#isGeneOntologyLoaded()
     */
    @Override
    public synchronized boolean isGeneOntologyLoaded() {

        return ready.get();
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#isReady()
     */
    @Override
    public boolean isReady() {
        return ready.get();
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#isRunning()
     */
    @Override
    public boolean isRunning() {
        return running.get();
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#listTerms()
     */
    @Override
    public Collection<OntologyTerm> listTerms() {
        return uri2Term.values();
    }

    /*
     * (non-Javadoc)
     * 
     * @see ubic.gemma.ontology.providers.GeneOntologyService#loadTermsInNameSpace(java.io.InputStream)
     */
    @Override
    public void loadTermsInNameSpace(InputStream is) {
        this.model = OntologyLoader.loadMemoryModel(is, null, OntModelSpec.OWL_MEM);
        Collection<OntologyResource> terms = OntologyLoader.initialize(null, model);
        this.indices.add(OntologyIndexer.indexOntology("GeneOntology", model));
        addTerms(terms);
    }

    /**
     * 
     */
    protected synchronized void forceLoadOntology() {
        initializeGeneOntology();
    }

    /**
     * @param url
     * @throws IOException
     */
    protected void loadTermsInNameSpace(String url) {
        this.model = OntologyLoader.loadMemoryModel(url, OntModelSpec.OWL_MEM);
        Collection<OntologyResource> terms = OntologyLoader.initialize(url, model);
        this.indices.add(OntologyIndexer.indexOntology(url.replaceFirst(".*/", "").replace(".owl", ""), model));
        addTerms(terms);
    }

    /**
     * @param newTerms
     */
    private void addTerms(Collection<OntologyResource> newTerms) {

        for (OntologyResource term : newTerms) {
            if (term.getUri() == null)
                continue;
            if (term instanceof OntologyTerm) {
                OntologyTerm ontTerm = (OntologyTerm) term;
                uri2Term.put(term.getUri(), ontTerm);
                for (String alternativeID : ontTerm.getAlternativeIds()) {
                    log.debug(toUri(alternativeID));
                    uri2Term.put(toUri(alternativeID), ontTerm);
                }
            }
        }
    }

    /**
     * @param entry
     * @param includePartOf
     * @return
     */
    private synchronized Collection<OntologyTerm> getAncestors(OntologyTerm entry, boolean includePartOf) {

        if (entry == null) {
            return new HashSet<OntologyTerm>();
        }

        Collection<OntologyTerm> ancestors = parentsCache.get(entry.getUri());
        if (ancestors == null) {
            ancestors = new HashSet<OntologyTerm>();

            Collection<OntologyTerm> parents = getParents(entry, includePartOf);
            if (parents != null) {
                for (OntologyTerm parent : parents) {
                    ancestors.add(parent);
                    ancestors.addAll(getAncestors(parent, includePartOf));
                }
            }

            ancestors = Collections.unmodifiableCollection(ancestors);
            parentsCache.put(entry.getUri(), ancestors);
        }
        return new HashSet<OntologyTerm>(ancestors);
    }

    /**
     * @param entry
     * @return Given an ontology term recursivly determines all the children and adds them to a cache (same as
     *         getAllParents but the recusive code is a little cleaner and doesn't use and accumulator)
     */
    private synchronized Collection<OntologyTerm> getDescendants(OntologyTerm entry, boolean includePartOf) {

        Collection<OntologyTerm> descendants = childrenCache.get(entry.getUri());
        if (descendants == null) {
            descendants = new HashSet<OntologyTerm>();

            Collection<OntologyTerm> children = getChildren(entry, includePartOf);
            if (children != null) {
                for (OntologyTerm child : children) {
                    descendants.add(child);
                    descendants.addAll(getDescendants(child, includePartOf));
                }
            }

            descendants = Collections.unmodifiableCollection(descendants);
            childrenCache.put(entry.getUri(), descendants);
        }
        return new HashSet<OntologyTerm>(descendants);

    }

    /**
     * Return terms to which the given term has a part_of relation (it is "part_of" them).
     * 
     * @param entry
     * @return
     */
    private Collection<OntologyTerm> getIsPartOf(OntologyTerm entry) {
        Collection<OntologyTerm> r = new HashSet<OntologyTerm>();
        String u = entry.getUri();
        String queryString = "SELECT ?x WHERE {  <" + u
                + ">  <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?v . "
                + "?v <http://www.w3.org/2002/07/owl#onProperty>  <" + PART_OF_URI + "> . "
                + "?v <http://www.w3.org/2002/07/owl#someValuesFrom> ?x . }";
        Query q = QueryFactory.create(queryString);
        QueryExecution qexec = QueryExecutionFactory.create(q, (Model) entry.getModel());
        try {
            ResultSet results = qexec.execSelect();
            while (results.hasNext()) {
                QuerySolution soln = results.nextSolution();
                Resource x = soln.getResource("x");
                if (x.isAnon())
                    continue; // some reasoners will return these.
                String uri = x.getURI();
                if (log.isDebugEnabled())
                    log.debug(entry + " is part of " + uri2Term.get(uri));
                r.add(uri2Term.get(uri));
            }
        } finally {
            qexec.close();
        }
        return r;
    }

    /**
     * Return terms which have "part_of" relation with the given term (they are "part_of" the given term).
     * 
     * @param entry
     * @return
     */
    private Collection<OntologyTerm> getPartsOf(OntologyTerm entry) {
        Collection<OntologyTerm> r = new HashSet<OntologyTerm>();
        String u = entry.getUri();
        String queryString = "SELECT ?x WHERE {" + "?x <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?v . "
                + "?v <http://www.w3.org/2002/07/owl#onProperty> <" + PART_OF_URI + ">  . "
                + "?v <http://www.w3.org/2002/07/owl#someValuesFrom> <" + u + "> . }";
        Query q = QueryFactory.create(queryString);
        QueryExecution qexec = QueryExecutionFactory.create(q, (Model) entry.getModel());
        try {
            ResultSet results = qexec.execSelect();
            while (results.hasNext()) {
                QuerySolution soln = results.nextSolution();
                Resource x = soln.getResource("x");
                String uri = x.getURI();
                if (x.isAnon())
                    continue; // some reasoners will return these.
                if (log.isDebugEnabled())
                    log.debug(uri2Term.get(uri) + " is part of " + entry);
                r.add(uri2Term.get(uri));
            }
        } finally {
            qexec.close();
        }
        return r;
    }

    /**
     * 
     */
    private synchronized void initializeGeneOntology() {

        Thread loadThread = new Thread(new Runnable() {
            @Override
            public void run() {
                running.set(true);
                uri2Term = new HashMap<String, OntologyTerm>();
                log.info("Loading Gene Ontology...");
                StopWatch loadTime = new StopWatch();
                loadTime.start();
                //
                try {
                    loadTermsInNameSpace(MF_URL);
                    log.info("Gene Ontology Molecular Function loaded, total of " + uri2Term.size() + " items in "
                            + loadTime.getTime() / 1000 + "s");

                    loadTermsInNameSpace(BP_URL);
                    log.info("Gene Ontology Biological Process loaded, total of " + uri2Term.size() + " items in "
                            + loadTime.getTime() / 1000 + "s");

                    loadTermsInNameSpace(CC_URL);
                    log.info("Gene Ontology Cellular Component loaded, total of " + uri2Term.size() + " items in "
                            + loadTime.getTime() / 1000 + "s");

                    ready.set(true);
                    running.set(false);

                    log.info("Done loading GO");
                    loadTime.stop();
                } catch (Throwable e) {
                    if (log != null)
                        log.error(e, e);// log call can break hot deploy
                    ready.set(false);
                    running.set(false);
                }
            }

        });

        if (running.get())
            return;
        loadThread.start();

    }

    private void logIds(String prefix, Collection<OntologyTerm> terms) {
        StringBuffer buf = new StringBuffer(prefix);
        buf.append(": [ ");
        Iterator<OntologyTerm> i = terms.iterator();
        while (i.hasNext()) {
            buf.append(GeneOntologyServiceImpl.asRegularGoId(i.next()));
            if (i.hasNext())
                buf.append(", ");
        }
        buf.append(" ]");
        log.trace(buf.toString());
    }

    @Override
    public void shutDown() {
        if (this.isReady()) {
            try {
                this.goTerms.clear();
                this.childrenCache.clear();
                this.parentsCache.clear();
                term2Aspect.clear();
                for (IndexLARQ l : indices) {
                    l.close();
                }

                this.model.close();
                this.model = null;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                ready.set(false);
                running.set(false);
            }

        }

    }

}