// OO jDREW - An Object Oriented extension of the Java Deductive Reasoning Engine for the Web // Copyright (C) 2011 // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA package org.ruleml.oojdrew; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.StringTokenizer; import nu.xom.ParsingException; import nu.xom.ValidityException; import org.apache.log4j.Level; import org.ruleml.oojdrew.TopDown.BackwardReasoner; import org.ruleml.oojdrew.parsing.POSLParser; import org.ruleml.oojdrew.parsing.ParseException; import org.ruleml.oojdrew.parsing.RDFSParser; import org.ruleml.oojdrew.parsing.RuleMLFormat; import org.ruleml.oojdrew.parsing.RuleMLParser; import org.ruleml.oojdrew.parsing.SubsumesException; import org.ruleml.oojdrew.util.DefiniteClause; import org.ruleml.oojdrew.util.TaxonomyQueryAPI; import org.ruleml.oojdrew.util.Util; import antlr.RecognitionException; import antlr.TokenStreamException; /** * This class implements the Complete OO jDREW API (COjDA) */ public class COjDA { private int varSize = 0; private Configuration config; private RuleMLParser rmlParser; private POSLParser poslParser; private TaxonomyQueryAPI taxonomyQueryAPI; private BackwardReasoner backwardReasoner; private boolean knowledgeBaseInitialized; private boolean taxonomyInitialized; public static COjDA getCOjDA() { // Construct dependencies Configuration config = new Config(COjDA.class); // Create the parsers RDFSParser rdfsParser = new RDFSParser(); POSLParser poslParser = new POSLParser(); RuleMLParser rmlParser = new RuleMLParser(config); TaxonomyQueryAPI taxonomyQueryAPI = new TaxonomyQueryAPI(); // Create the reasoning engine BackwardReasoner backwardReasoner = new BackwardReasoner(); // Create TopDownApp COjDA cojda = new COjDA(config, poslParser, rmlParser, taxonomyQueryAPI, backwardReasoner); return cojda; } private COjDA(Configuration config, POSLParser poslParser, RuleMLParser rmlParser, TaxonomyQueryAPI taxonomyQueryAPI, BackwardReasoner backwardReasoner) { this.config = config; // log4j is not intended for API usage this.config.setLogLevel(Level.OFF); this.poslParser = poslParser; this.rmlParser = rmlParser; this.taxonomyQueryAPI = taxonomyQueryAPI; this.backwardReasoner = backwardReasoner; knowledgeBaseInitialized = false; taxonomyInitialized = false; this.config.addPreferenceChangeListener(rmlParser); } /** * Configure the API * * @param rmlFormat * RuleML format which should be used (e.g. RuleML 1.0) * * @param enableValidation * If true, the XML validation will be enabled */ public void configureAPI(RuleMLFormat rmlFormat) { config.setSelectedRuleMLFormat(rmlFormat); } /** * Parse a given knowledge base in the given syntax format and initialize a * backward reasoner using the parsed knowledge base. * * @param syntaxFormat * The syntax format of the knowledge base * * @param knowledgeBase * The knowledge base which should be parsed * * @throws ParseException * @throws ParsingException * @throws IOException * @throws RecognitionException * @throws TokenStreamException */ public void initializeKnowledgeBase(SyntaxFormat syntaxFormat, String knowledgeBase) throws ParseException, ParsingException, IOException, RecognitionException, TokenStreamException { if (syntaxFormat == SyntaxFormat.RDFS) { throw new ParseException("RDFS cannot be used for knowledge base representation."); } Iterator kbIterator; if (syntaxFormat == SyntaxFormat.POSL) { poslParser.parseDefiniteClauses(knowledgeBase); kbIterator = poslParser.iterator(); } else { rmlParser.parseRuleMLString(knowledgeBase); kbIterator = rmlParser.iterator(); } initializeBackwardReasoner(kbIterator); knowledgeBaseInitialized = true; } /** * Parse a given knowledge base in the given syntax format and initialize a * backward reasoner using the parsed knowledge base. * * @see COjDA#initializeKnowledgeBase(SyntaxFormat, String) * */ public void initializeKnowledgeBase(SyntaxFormat syntaxFormat, File knowledgeBase) throws FileNotFoundException, IOException, RecognitionException, TokenStreamException, ParseException, ParsingException { String fileContent = Util.readFile(knowledgeBase); initializeKnowledgeBase(syntaxFormat, fileContent); } /** * Initialize a taxonomy (POSL or RDFS) * * @param syntaxFormat * The syntax format of the taxonomy * * @param taxonomy * The taxonomy which should be initialized * * @throws ValidityException * @throws ParseException * @throws ParsingException * @throws IOException * @throws SubsumesException */ public void initializeTaxonomy(SyntaxFormat syntaxFormat, String taxonomy) throws ValidityException, ParseException, ParsingException, IOException, SubsumesException { if (syntaxFormat == SyntaxFormat.RULEML) { throw new ParseException("RuleML cannot be used for taxonomy representation."); } taxonomyQueryAPI.initializeTaxonomy(syntaxFormat, taxonomy); taxonomyInitialized = true; } /** * Initialize a POSL or a RDFS taxonomy * * @see COjDA#initializeTaxonomy(SyntaxFormat, String) */ public void initializeTaxonomy(SyntaxFormat syntaxFormat, File taxonomy) throws ValidityException, ParseException, ParsingException, IOException, SubsumesException { String fileContent = Util.readFile(taxonomy); initializeTaxonomy(syntaxFormat, fileContent); } /** * Issue a query on the knowledge base in either POSL or RuleML syntax * * @param query * The POSL or RuleML knowledge base query as a string. * * @return The answer as a string formatted RuleML expression. * * @throws RecognitionException * @throws TokenStreamException * @throws IOException * @throws ParsingException * @throws ParseException */ public String issueKnowledgebaseQuery(SyntaxFormat syntaxFormat, String query) throws RecognitionException, TokenStreamException, ParseException, ParsingException, IOException { if (!knowledgeBaseInitialized) { throw new ParseException("No knowledge base available. Please initialize a knowledge base first."); } DefiniteClause definitiveClause; if (syntaxFormat == SyntaxFormat.POSL) { definitiveClause = poslParser.parseQueryString(query); } else { definitiveClause = rmlParser.parseRuleMLQuery(query); } Iterator solutionIterator = backwardReasoner.iterativeDepthFirstSolutionIterator(definitiveClause); ArrayList<BindingPair> solutionPairs = generateBindingObjects(solutionIterator); return generateRuleMLAnswerExpression(solutionPairs); } /** * Issue a query on the knowledge base in either POSL or RuleML syntax * * @see COjDA#issueKnowledgebaseQuery(SyntaxFormat, String) */ public String issueKnowledgebaseQuery(SyntaxFormat syntaxFormat, File query) throws RecognitionException, TokenStreamException, ParseException, ParsingException, IOException { String fileContent = Util.readFile(query); return issueKnowledgebaseQuery(syntaxFormat, fileContent); } /** * Issue a query on the taxonomy by using either a POSL or a RuleML query. * * @param query * The POSL or RuleML taxonomy query as a string. * * @return The answer as a string formatted RuleML expression. * * @throws ValidityException * @throws ParseException * @throws ParsingException * @throws IOException * @throws Exception */ public String issueTaxonomyQuery(SyntaxFormat syntaxFormat, String query) throws ValidityException, ParseException, ParsingException, Exception { if (!taxonomyInitialized) { throw new ParseException("No taxonomy available. Please initialize a taxonomy first."); } return taxonomyQueryAPI.executeQuery(syntaxFormat, query); } /** * Issue a query on the taxonomy by using either a POSL or a RuleML query. * * @see COjDA#issueTaxonomyQuery(SyntaxFormat, String) */ public String issusTaxonomyQuery_RuleML(SyntaxFormat syntaxFormat, File query) throws ValidityException, ParseException, ParsingException, IOException, Exception { String fileContent = Util.readFile(query); return issueTaxonomyQuery(syntaxFormat, fileContent); } /** * This method will initialize the OO jDREW reasoning engine. * * @param clauses * The facts to initialize OO jDREW with. */ private void initializeBackwardReasoner(Iterator clauses) { backwardReasoner = new BackwardReasoner(); backwardReasoner.loadClauses(clauses); backwardReasoner = new BackwardReasoner(backwardReasoner.clauses, backwardReasoner.oids); } /** * This method will generate the Binding Pairs. * * @param solutions * The results of the queries. * * @return An array list of all the binding pairs. */ private ArrayList<BindingPair> generateBindingObjects(Iterator solutions) { ArrayList<BindingPair> pairs = new ArrayList<BindingPair>(); while (solutions.hasNext()) { BackwardReasoner.GoalList gl = (BackwardReasoner.GoalList) solutions.next(); Hashtable varbind = gl.varBindings; varSize = varbind.size(); Enumeration e = varbind.keys(); while (e.hasMoreElements()) { Object k = e.nextElement(); String val = (String) varbind.get(k); String ks = (String) k; ks = ks.substring(1); StringTokenizer st = new StringTokenizer(ks, ":"); if (st.countTokens() == 2) { String var = st.nextToken().trim(); String type = st.nextToken().trim(); ks = "<Var type=\"" + type + "\">" + var + "</Var>"; } else { ks = "<Var>" + ks + "</Var>"; } BindingPair bp = new BindingPair(ks, val); pairs.add(bp); } } return pairs; } /** * This method will generate the RuleML answer expression as the solution to * a query * * @param solutionPairs * All the solutions to the query. * * @return RuleML answer expression based on the solutions given. */ private String generateRuleMLAnswerExpression(ArrayList<BindingPair> solutionPairs) { String answer = "<RuleML>\n\t<Answer>\n"; for (int i = 0; i < solutionPairs.size(); i++) { if (i % varSize == 0) { answer = answer + "\t\t<Rulebase>\n"; } answer = answer + "\t\t\t<Equal>\n"; BindingPair pair = solutionPairs.get(i); answer = answer + "\t\t\t\t" + pair.getVariable() + "\n"; StringTokenizer st = new StringTokenizer(pair.getValue(), "\n"); while (st.hasMoreTokens()) { answer = answer + "\t\t\t\t" + st.nextToken() + "\n"; } answer = answer + "\t\t\t</Equal>"; if (i % varSize == varSize - 1) { answer = answer + "\n\t\t</Rulebase>"; } if (!(i == solutionPairs.size() - 1)) { answer = answer + "\n"; } } answer += "\n\t</Answer>\n</RuleML>"; return answer; } }