package org.phenoscape.controller;
import java.beans.XMLDecoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JOptionPane;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.bbop.dataadapter.DataAdapterException;
import org.bbop.framework.GUIManager;
import org.obo.annotation.base.OntologyConfiguration;
import org.obo.annotation.base.OntologySource;
import org.obo.annotation.base.TermSet;
import org.obo.app.util.URLProxy;
import org.obo.dataadapter.OBOAdapter;
import org.obo.dataadapter.OBOFileAdapter;
import org.obo.datamodel.IdentifiedObject;
import org.obo.datamodel.OBOClass;
import org.obo.datamodel.OBOSession;
import org.obo.datamodel.impl.OBOSessionImpl;
import org.obo.filters.Filter;
import org.oboedit.controller.SessionManager;
import org.phenoscape.util.ProvisionalTermUtil;
/**
* @author Jim Balhoff
*/
public class OntologyController {
private static final String ENTITY_FILTER = "entities";
private static final String QUALITY_FILTER = "qualities";
private static final String RELATION_FILTER = "relations";
private static final String UNIT_FILTER = "units";
private static final String TAXON_FILTER = "taxa";
private static final String MUSEUM_FILTER = "museums";
private static final String PC_FILLERS_FILTER = "postcomposition";
private static final String ALL_TERMS = "allterms";
private static final String ALL_TERMS_WITHOUT_PROVISIONAL = "allpublicterms";
private File overridingFiltersFolder = new File(GUIManager.getPrefsDir(), "Filters");
private TermSet entityTermSet = null;
private TermSet qualityTermSet = null;
private TermSet taxonTermSet = null;
private TermSet collectionTermSet = null;
private TermSet unitTermSet = null;
private TermSet relationsTermSet = null;
private TermSet pcFillersTermSet = null;
private TermSet allTermsSet = null;
private TermSet allTermsWithoutProvisionalSet = null;
private final OntologyConfiguration config;
public OntologyController(OntologyConfiguration configuration) {
this.config = configuration;
final OBOFileAdapter fileAdapter = new OBOFileAdapter();
OBOFileAdapter.OBOAdapterConfiguration adapterConfig = new OBOFileAdapter.OBOAdapterConfiguration();
adapterConfig.setReadPaths(Arrays.asList(this.getPaths()));
adapterConfig.setBasicSave(false);
adapterConfig.setAllowDangling(true);
adapterConfig.setFollowImports(false); // this is required because OBO currently fails if it tries to follow an import and there is no network connection
try {
SessionManager.getManager().setSession(fileAdapter.doOperation(OBOAdapter.READ_ONTOLOGY, adapterConfig, null));
} catch (DataAdapterException e) {
JOptionPane.showMessageDialog(null, "An error occurred while loading ontologies: " + e.getLocalizedMessage(), "Error Loading Ontologies", JOptionPane.ERROR_MESSAGE);
log().fatal("Failed to load ontologies", e);
SessionManager.getManager().setSession(new OBOSessionImpl());
this.eraseOntologyCache();
}
this.loadProvisionalTerms();
this.prefetchTermSets();
}
private String[] getPaths() {
//TODO make proxy location configurable
URLProxy proxy = new URLProxy(new File(GUIManager.getPrefsDir(),"Ontology Cache"));
final List<String> urls = new ArrayList<String>();
for (OntologySource source : this.config.getSources()) {
try {
final File localFile = proxy.get(source.getURL());
urls.add(localFile.toURI().toString());
} catch (IOException e) {
//TODO alert user somehow
log().error("Unable to read ontology at: " + source.getURL(), e);
}
}
return urls.toArray(new String[] {});
}
public OBOSession getOBOSession() {
return SessionManager.getManager().getSession();
}
public TermSet getTaxonTermSet() {
if (this.taxonTermSet == null) {
final TermSet terms = this.makeTermSet();
terms.setTermFilter(this.loadFilterWithName(TAXON_FILTER));
this.taxonTermSet = terms;
}
return this.taxonTermSet;
}
public TermSet getCollectionTermSet() {
if (this.collectionTermSet == null) {
final TermSet terms = this.makeTermSet();
terms.setTermFilter(this.loadFilterWithName(MUSEUM_FILTER));
this.collectionTermSet = terms;
}
return this.collectionTermSet;
}
public TermSet getEntityTermSet() {
if (this.entityTermSet == null) {
final TermSet terms = this.makeTermSet();
terms.setTermFilter(this.loadFilterWithName(ENTITY_FILTER));
this.entityTermSet = terms;
}
return this.entityTermSet;
}
public TermSet getQualityTermSet() {
if (this.qualityTermSet == null) {
final TermSet terms = this.makeTermSet();
terms.setTermFilter(this.loadFilterWithName(QUALITY_FILTER));
this.qualityTermSet = terms;
}
return this.qualityTermSet;
}
public TermSet getRelatedEntityTermSet() {
return this.getEntityTermSet();
}
public TermSet getUnitTermSet() {
if (this.unitTermSet == null) {
final TermSet terms = this.makeTermSet();
terms.setTermFilter(this.loadFilterWithName(UNIT_FILTER));
this.unitTermSet = terms;
}
return this.unitTermSet;
}
public TermSet getRelationsTermSet() {
if (this.relationsTermSet == null) {
final TermSet set = this.makeTermSet();
set.setTermFilter(this.loadFilterWithName(RELATION_FILTER));
this.relationsTermSet = set;
}
return this.relationsTermSet;
}
public TermSet getPostCompositionFillersTermSet() {
if (this.pcFillersTermSet == null) {
final TermSet set = this.makeTermSet();
set.setTermFilter(this.loadFilterWithName(PC_FILLERS_FILTER));
this.pcFillersTermSet = set;
}
return this.pcFillersTermSet;
}
public TermSet getAllTermsSet() {
if (this.allTermsSet == null) {
final TermSet set = this.makeTermSet();
set.setTermFilter(this.loadFilterWithName(ALL_TERMS));
this.allTermsSet = set;
}
return this.allTermsSet;
}
public TermSet getAllTermsSetWithoutProvisional() {
if (this.allTermsWithoutProvisionalSet == null) {
final TermSet set = this.makeTermSet();
set.setTermFilter(this.loadFilterWithName(ALL_TERMS_WITHOUT_PROVISIONAL));
this.allTermsWithoutProvisionalSet = set;
}
return this.allTermsWithoutProvisionalSet;
}
public File getOverridingFiltersFolder() {
return this.overridingFiltersFolder;
}
public void setOverridingFiltersFolder(File folder) {
this.overridingFiltersFolder = folder;
}
private TermSet makeTermSet() {
return new TermSet(this.getOBOSession(), SessionManager.getManager().getReasoner());
}
/**
* This is just a startup "optimization" - it makes the term searches
* happen while the ontology loading panel is displayed. This reduces
* the blank time between that panel disappearing and the interface being
* displayed.
*/
private void prefetchTermSets() {
this.getEntityTermSet().getTerms();
this.getTaxonTermSet().getTerms();
this.getCollectionTermSet().getTerms();
this.getUnitTermSet().getTerms();
this.getRelationsTermSet().getTerms();
this.getQualityTermSet().getTerms();
this.getRelatedEntityTermSet().getTerms();
this.getPostCompositionFillersTermSet().getTerms();
this.getAllTermsSet().getTerms();
}
private Filter<IdentifiedObject> loadFilterWithName(String filterName) {
final String filename = filterName + ".xml";
final File filterFile = new File(this.getOverridingFiltersFolder(), filename);
if (filterFile.exists()) {
return this.loadFilter(filterFile);
} else {
return this.loadFilterFromResource("/org/phenoscape/filters/" + filename);
}
}
private Filter<IdentifiedObject> loadFilterFromResource(String resourcePath) {
return this.loadFilter(this.getClass().getResourceAsStream(resourcePath));
}
private Filter<IdentifiedObject> loadFilter(File xmlFile) {
try {
return this.loadFilter(new FileInputStream(xmlFile));
} catch (FileNotFoundException e) {
log().error("Could not find specified filter file", e);
}
return null;
}
@SuppressWarnings("unchecked")
private Filter<IdentifiedObject> loadFilter(InputStream stream) {
final XMLDecoder d = new XMLDecoder(stream);
final Filter<IdentifiedObject> result = (Filter<IdentifiedObject>) d.readObject();
d.close();
return result;
}
private void loadProvisionalTerms() {
try {
final List<OBOClass> terms = ProvisionalTermUtil.getProvisionalTerms(this.getOBOSession());
for (OBOClass term : terms) {
this.getOBOSession().addObject(term);
}
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void eraseOntologyCache() {
final File cacheDir = new File(GUIManager.getPrefsDir(),"Ontology Cache");
try {
FileUtils.deleteDirectory(cacheDir);
} catch (IOException e) {
log().error("Failed to delete ontology cache after load error.", e);
}
}
private Logger log() {
return Logger.getLogger(this.getClass());
}
public void invalidateAllTermSets() {
this.getEntityTermSet().invalidateTerms();
this.getTaxonTermSet().invalidateTerms();
this.getCollectionTermSet().invalidateTerms();
this.getUnitTermSet().invalidateTerms();
this.getRelationsTermSet().invalidateTerms();
this.getQualityTermSet().invalidateTerms();
this.getRelatedEntityTermSet().invalidateTerms();
this.getPostCompositionFillersTermSet().invalidateTerms();
this.getAllTermsSet().invalidateTerms();
}
}