view OPPL/Tool.java @ 8:40adbcb2a7cc

Added merge function and FaCT++ support. Improved OBO render
author Mikel Egaña Aranguren <mikel-egana-aranguren@toolshed.g2.bx.psu.edu>
date Tue, 11 Oct 2011 11:09:52 +0200
parents 756f1f5798bf
children 14bfd77f8520
line wrap: on
line source

/**
 * Copyright (C) 2011, Mikel Egaña Aranguren
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package es.upm.fi.dia.oeg.oppl.galaxy;

import java.io.BufferedWriter;
import java.io.File;
//import java.io.PrintWriter;
//import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
//import java.util.logging.Level;
import java.util.logging.Logger;

import org.coode.oppl.ChangeExtractor;
import org.coode.oppl.OPPLParser;
import org.coode.oppl.OPPLScript;
import org.coode.oppl.ParserFactory;
import org.coode.oppl.exceptions.QuickFailRuntimeExceptionHandler;
//import org.coode.oppl.log.Logging;
import org.coode.owlapi.obo.parser.OBOOntologyFormat;
import org.coode.parsers.ErrorListener;
import org.coode.parsers.LoggerErrorListener;
//import org.obolibrary.obo2owl.Owl2Obo;
//import org.obolibrary.oboformat.model.OBODoc;
//import org.obolibrary.oboformat.writer.OBOFormatWriter;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.RDFXMLOntologyFormat;
import org.semanticweb.owlapi.io.SystemOutDocumentTarget;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationProperty;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLAxiomChange;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLLiteral;
//import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChange;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyIRIMapper;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;
//import org.semanticweb.owlapi.owllink.OWLlinkHTTPXMLReasonerFactory;
import org.semanticweb.owlapi.reasoner.InferenceType;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
import org.semanticweb.owlapi.util.InferredAxiomGenerator;
import org.semanticweb.owlapi.util.InferredOntologyGenerator;
import org.semanticweb.owlapi.util.InferredSubClassAxiomGenerator;
import org.semanticweb.owlapi.util.OWLEntityRenamer;
import org.semanticweb.owlapi.util.OWLOntologyMerger;
import org.semanticweb.owlapi.util.SimpleIRIMapper;
import org.semanticweb.owlapi.vocab.OWL2Datatype;
import org.semanticweb.owlapi.vocab.OWLRDFVocabulary;

import uk.ac.manchester.cs.factplusplus.owlapiv3.FaCTPlusPlusReasonerFactory;

import com.clarkparsia.pellet.owlapiv3.PelletReasonerFactory;

import org.semanticweb.HermiT.Reasoner;

/**
 * @author Mikel Egaña Aranguren
 */
public class Tool {

	/**
	 * @throws OWLOntologyCreationException 
	 * @throws OWLOntologyStorageException 
	 * @throws IOException 
	 * @throws URISyntaxException 
	 */
	public static void main(String[] args) throws OWLOntologyCreationException, OWLOntologyStorageException, IOException, URISyntaxException {		
		// Get the arguments from command-line
		String OWLFilePath = args [0]; 
		String OPPL_script_file = args [1];
		String Output_format = args [2]; // OWL|OBO
		String Add_inferred = args [3]; // AddInferred|Whatever
		String imports_file_path = args [4]; // NoImports|Flat tab delimited file: URI	Document URI
		String reasoner_type = args [5]; // Pellet|FaCTPlusPlus|HermiT
		String merge_URI = args [6]; // NoMerge|URI for merged ontology
		
		// Load the main ontology		
		File owl_file = new File(OWLFilePath);
		OWLOntologyManager manager = OWLManager.createOWLOntologyManager(); 
		
		// Load the imports if any
		if(!imports_file_path.equals("NoImports")){
			File imports_file = new File(imports_file_path);
			Scanner imports_input = new Scanner(imports_file);
			while(imports_input.hasNext()){
			    String nextLine = imports_input.nextLine();
			    if(!nextLine.startsWith("#")){
				    String [] URI_documentURI = nextLine.split("\t");	
				    IRI ontology_IRI = IRI.create(URI_documentURI[0]);
					IRI document_IRI = IRI.create("file://" + URI_documentURI[1]);	
					OWLOntologyIRIMapper iriMapper = new SimpleIRIMapper(ontology_IRI,document_IRI);
					manager.addIRIMapper(iriMapper);
				}
			}
			imports_input.close();
		}
		OWLOntology OWL_ontology = manager.loadOntologyFromOntologyDocument(owl_file);
		
		// Reasoner
		OWLReasonerFactory reasonerFactory = null;
		OWLReasoner reasoner = null;
		
		// Pellet
		if(reasoner_type.equals("Pellet")){
			reasonerFactory = new PelletReasonerFactory(); 
			reasoner = reasonerFactory.createReasoner(OWL_ontology);
		}
		// FaCTPlusPlus
		else if (reasoner_type.equals("FaCTPlusPlus")){
			reasonerFactory = new FaCTPlusPlusReasonerFactory();
			reasoner = reasonerFactory.createReasoner(OWL_ontology);
		}
		// HermiT
		else{
			reasonerFactory = new Reasoner.ReasonerFactory();
			reasoner = reasonerFactory.createReasoner(OWL_ontology);
		}
		
		// OWLLink: The problem is that Racer, for example, listens in 8080, the same port as Galaxy
		// I have to change Racer settings and OWLLink settings
//		OWLlinkHTTPXMLReasonerFactory factory = new OWLlinkHTTPXMLReasonerFactory();
//		reasoner = factory.createReasoner(OWL_ontology);
		
		// Load the flat file with script in memory
		String OPPL_script_source = "";
		File file = new File(OPPL_script_file);
		Scanner input = new Scanner(file);
		while(input.hasNext()) {
		    String nextToken = input.next();
		    OPPL_script_source = OPPL_script_source + " " + nextToken;
		}
		input.close();
	
		// Parse the OPPL script
		ParserFactory parserFactory = new ParserFactory(manager, OWL_ontology, reasoner); 
		Logger logger = Logger.getLogger(Tool.class.getName());
//		Logging.getQueryLogger().setLevel(Level.OFF); // The normal messages are errors for galaxy (Fixed in Galaxy by 2 > /dev/null)
		ErrorListener errorListener = (ErrorListener)new LoggerErrorListener(logger);
		OPPLParser opplparser = parserFactory.build(errorListener);
		OPPLScript OPPLscript = opplparser.parse(OPPL_script_source);
			
		// Execute the script
		ChangeExtractor extractor = new ChangeExtractor(new QuickFailRuntimeExceptionHandler(), true);
		List<OWLAxiomChange> changes = extractor.visit(OPPLscript);
		manager.applyChanges(changes);
		
		// Add the inferred axioms as asserted axioms to the original ontology
		if(Add_inferred.equals("AddInferred")){
			reasoner.precomputeInferences(InferenceType.CLASS_HIERARCHY);
			List<InferredAxiomGenerator<? extends OWLAxiom>> gens = new ArrayList<InferredAxiomGenerator<? extends OWLAxiom>>();
			gens.add(new InferredSubClassAxiomGenerator());
			InferredOntologyGenerator iog = new InferredOntologyGenerator(reasoner, gens);
			iog.fillOntology(manager, OWL_ontology);	
		}
		
		// Print the ontology to the standard output so other galaxy tools can operate on it
		
		// Do not merge ontologies
		if(merge_URI.equals("NoMerge")){
			saveOntology(manager, OWL_ontology, Output_format);
		}
		// Merge ontologies
		else{	
			OWLOntologyMerger merger = new OWLOntologyMerger(manager);
			IRI mergedOntologyIRI = IRI.create(merge_URI);
			OWLOntology merged = merger.createMergedOntology(manager, mergedOntologyIRI);
			saveOntology(manager, merged, Output_format);
		}
	}
	
	private static void saveOntology (OWLOntologyManager manager, OWLOntology ontology, String Format) throws OWLOntologyStorageException, IOException, URISyntaxException {
		
		// OBO format
		if(Format.equals("OBO")){
			
			// OWL API generates bad OBO but OBOformat doesn't work either so I correct the OWL API problems (More predictable) in a temporary file
			// Very inefficient but no time for another solution
			
			OWLDataFactory factory = manager.getOWLDataFactory();
			
			OWLEntityRenamer renamer = new OWLEntityRenamer (manager, manager.getOntologies());
			OWLAnnotationProperty label = factory.getOWLAnnotationProperty(OWLRDFVocabulary.RDFS_LABEL.getIRI());
			
			for(OWLClass cls : ontology.getClassesInSignature()){
				// Remove annotations (OWL API generates bad OBO annotations)
				
				// Keep rdfs:label
				String class_name = null;
				for (OWLAnnotation annotation : cls.getAnnotations(ontology, label)) {
	                if (annotation.getValue() instanceof OWLLiteral) {
	                    OWLLiteral val = (OWLLiteral) annotation.getValue();
	                    class_name = val.getLiteral();
	                }
	            }
							
//				I have to remove all the annotations cause I don't know which ones are rendered properly
				manager.removeAxioms(ontology,ontology.getAnnotationAssertionAxioms(cls.getIRI()));
				
				// Add rdfs:label again
				OWLAnnotation labelAnno = factory.getOWLAnnotation(factory.getOWLAnnotationProperty(
				OWLRDFVocabulary.RDFS_LABEL.getIRI()),factory.getOWLLiteral(class_name,OWL2Datatype.XSD_STRING));
				OWLAxiom ax = factory.getOWLAnnotationAssertionAxiom(cls.getIRI(), labelAnno);
				manager.applyChange(new AddAxiom(ontology, ax));
				
				// Rename entities
				String cls_IRI = cls.getIRI().toString();
				String cls_proper_IRI = cls_IRI.replace("_", ":");
				List<OWLOntologyChange> changes = renamer.changeIRI(cls, IRI.create(cls_proper_IRI));
				manager.applyChanges(changes);
			}
			
			File file = new File("tmp.obo");
			manager.saveOntology(ontology, new OBOOntologyFormat(), IRI.create(file.toURI()));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));		
			Scanner input = new Scanner(file);
			String buffer = "";

			while(input.hasNext()){
				String nextLine = input.nextLine();
				if(nextLine.contains("[Term]") || nextLine.contains("[Typedef]")){
					if(buffer.isEmpty()){
						bw.write(buffer);
						bw.newLine();
					}
				}
				if(!nextLine.contains("is_a: Thing") && !nextLine.contains("auto-generated-by:") && !nextLine.contains("id_space:") && !nextLine.contains("! ----")){
					if(!nextLine.isEmpty() && !buffer.contains("relationship:")){
						bw.write(nextLine);
						bw.newLine();
					}
				}
				buffer = nextLine;
			}
			input.close();
			bw.close();
			file.delete();
		}
		
		//OWL format
		else{
			manager.saveOntology(ontology, new RDFXMLOntologyFormat(), new SystemOutDocumentTarget());
		}
	}
}