blob: 111f44b1e1c80f0814763f160ada4cc619edacd4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 jena;
import static org.apache.jena.atlas.logging.LogCtl.setCmdLogging;
import java.util.*;
import java.io.*;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.jena.graph.* ;
import org.apache.jena.rdf.model.* ;
import org.apache.jena.reasoner.Reasoner ;
import org.apache.jena.reasoner.rulesys.* ;
import org.apache.jena.reasoner.rulesys.builtins.BaseBuiltin ;
import org.apache.jena.util.FileManager ;
import org.apache.jena.util.FileUtils ;
/**
* General command line utility to process one RDF file into another
* by application of a set of forward chaining rules.
* <pre>
* Usage: RuleMap [-il inlang] [-ol outlang] [-d] rulefile infile
* </pre>
* The resulting RDF data is written to stdout in format <code>outlang</code>
* (default N3). If <code>-d</code> is given then only the deductions
* generated by the rules are output. Otherwise all data including any input
* data (other than any removed triples) is output.
* <p>
* Rules are permitted an additional action "deduce" which forces triples
* to be added to the deductions graph even if they are already known (for use
* in deductions only mode).
* </p>
*/
public class RuleMap {
static { setCmdLogging() ; }
/**
* Load a set of rule definitions including processing of
* comment lines and any initial prefix definition lines.
* Also notes the prefix definitions for adding to a later inf model.
*/
public static List<Rule> loadRules(String filename, Map<String, String> prefixes) {
String fname = filename;
if (fname.startsWith("file:///")) {
fname = File.separator + fname.substring(8);
} else if (fname.startsWith("file:/")) {
fname = File.separator + fname.substring(6);
} else if (fname.startsWith("file:")) {
fname = fname.substring(5);
}
BufferedReader src = FileUtils.openResourceFile(fname);
return loadRules(src, prefixes);
}
/**
* Load a set of rule definitions including processing of
* comment lines and any initial prefix definition lines.
* Also notes the prefix definitions for adding to a later inf model.
*/
public static List<Rule> loadRules(BufferedReader src, Map<String, String> prefixes) {
Rule.Parser parser = Rule.rulesParserFromReader(src);
List<Rule> rules = Rule.parseRules(parser);
prefixes.putAll(parser.getPrefixMap());
return rules;
}
/**
* Internal implementation of the "deduce" primitve.
* This takes the form <code> ... -> deduce(s, p, o)</code>
*/
static class Deduce extends BaseBuiltin {
/**
* Return a name for this builtin, normally this will be the name of the
* functor that will be used to invoke it.
*/
@Override
public String getName() {
return "deduce";
}
/**
* Return the expected number of arguments for this functor or 0 if the number is flexible.
*/
@Override
public int getArgLength() {
return 3;
}
/**
* This method is invoked when the builtin is called in a rule head.
* Such a use is only valid in a forward rule.
* @param args the array of argument values for the builtin, this is an array
* of Nodes.
* @param length the length of the argument list, may be less than the length of the args array
* for some rule engines
* @param context an execution context giving access to other relevant data
*/
@Override
public void headAction(Node[] args, int length, RuleContext context) {
if (context.getGraph() instanceof FBRuleInfGraph) {
Triple t = new Triple(args[0], args[1], args[2]);
((FBRuleInfGraph)context.getGraph()).addDeduction(t);
} else {
throw new BuiltinException(this, context, "Only usable in FBrule graphs");
}
}
}
/**
* General command line utility to process one RDF file into another
* by application of a set of forward chaining rules.
* <pre>
* Usage: RuleMap [-il inlang] [-ol outlang] -d infile rulefile
* </pre>
*/
public static void main(String[] args) {
try {
// Parse the command line
String usage = "Usage: RuleMap [-il inlang] [-ol outlang] [-d] rulefile infile (- for stdin)";
final CommandLineParser parser = new DefaultParser();
Options options = new Options().addOption("il", "inputLang", true, "input language")
.addOption("ol", "outputLang", true, "output language").addOption("d", "Deductions only?");
CommandLine cl = parser.parse(options, args);
final List<String> filenameArgs = cl.getArgList();
if (filenameArgs.size() != 2) {
System.err.println(usage);
System.exit(1);
}
String inLang = cl.getOptionValue("inputLang");
String fname = filenameArgs.get(1);
Model inModel = null;
if (fname.equals("-")) {
inModel = ModelFactory.createDefaultModel();
inModel.read(System.in, null, inLang);
} else {
inModel = FileManager.get().loadModel(fname, inLang);
}
String outLang = cl.hasOption("outputLang") ? cl.getOptionValue("outputLang") : "N3";
boolean deductionsOnly = cl.hasOption('d');
// Fetch the rule set and create the reasoner
BuiltinRegistry.theRegistry.register(new Deduce());
Map<String, String> prefixes = new HashMap<>();
List<Rule> rules = loadRules(filenameArgs.get(0), prefixes);
Reasoner reasoner = new GenericRuleReasoner(rules);
// Process
InfModel infModel = ModelFactory.createInfModel(reasoner, inModel);
infModel.prepare();
infModel.setNsPrefixes(prefixes);
// Output
try ( PrintWriter writer = new PrintWriter(System.out) ) {
if (deductionsOnly) {
Model deductions = infModel.getDeductionsModel();
deductions.setNsPrefixes(prefixes);
deductions.setNsPrefixes(inModel);
deductions.write(writer, outLang);
} else {
infModel.write(writer, outLang);
}
}
} catch (Throwable t) {
System.err.println("An error occured: \n" + t);
t.printStackTrace();
}
}
}