From d04e2839689c4291afb4beb9a1913bb38fac1cd1 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Sat, 30 Jan 2021 10:46:23 +0000 Subject: Introduce a better system to handle command line input --- src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala | 200 ++++++++++++++++++-------- 1 file changed, 142 insertions(+), 58 deletions(-) (limited to 'src/main/scala/uk/ac/ox/cs') diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala index bf96a31..909cfdd 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala @@ -10,6 +10,106 @@ import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery import util.{Logger, RDFoxUtil, RSA} import sparql.ConjunctiveQuery +case class RSAOption[+T](opt: T) { + def get[T]: T = opt.asInstanceOf[T] +} + +object RSAConfig { + type Config = Map[Symbol, RSAOption[Any]] + + private implicit def toRSAOption[T](opt: T) = RSAOption[T](opt) + + /** Help message */ + private val help: String = """ + rsacomb - combined approach for CQ answering for RSA ontologies. + + USAGE + rsacomb [OPTIONS] [ ...] + + -h | -? | --help + print this help message + + --rsacheck-only + only perform the RSA check without performing any query answering. + + -q | --query + path to a file containing a single SPARQL query + + + file containing the ontology + + + one or more data files + + """ + + /** Default config values */ + private val default = Map( + 'rsacheckonly -> RSAOption[Boolean](false) + ) + + /** Utility to exit the program with a custom message on stderr. + * + * The program will exit with error code 1 after printing the help + * message. + * + * @param msg message printed to stderr. + */ + private def exit(msg: String): Nothing = { + System.err.println(msg) + System.err.println() + System.err.println(help) + sys.exit(1) + } + + /** Parse arguments with default options + * + * @param args arguments list + */ + def parse(args: List[String]): Config = parse(args, default) + + /** Parse arguments + * + * @param args arguments list + * @param config default configuration + */ + def parse(args: List[String], config: Config): Config = { + args match { + case flag @ ("-h" | "-?" | "--help") :: _ => { + println(help) + sys.exit(0) + } + case "--rsacheck-only" :: tail => + parse(tail, config ++ Map('rsacheckonly -> true)) + case flag @ ("-q" | "--query") :: _query :: tail => { + val query = new File(_query) + if (!query.isFile) + exit(s"'$query' is not a valid filename.") + parse(tail, config ++ Map('query -> query)) + } + case _ontology :: _data => { + val ontology = new File(_ontology) + val data = _data.map(new File(_)) + (ontology :: data) foreach { (file) => + if (!file.isFile) + exit(s"'$file' is not a valid filename.") + } + finalise(config ++ Map('ontology -> ontology, 'data -> data)) + } + case a => exit(s"Invalid sequence of arguments '${a.mkString(" ")}'.") + } + } + + /** Perform final checks on parsed options */ + private def finalise(config: Config): Config = { + // Query file is mandatory unless only the RSA check is required. + if (!config('rsacheckonly).get[Boolean] && !config.contains('query)) + exit(s"Query file was not provided.") + + config + } +} + /** Entry point of the program. * * The executable expects a SPARQL query and a non-empty sequence of @@ -24,72 +124,56 @@ import sparql.ConjunctiveQuery */ object RSAComb extends App { - val help: String = """ - rsacomb - combined approach for CQ answering for RSA ontologies. - - USAGE - rsacomb [...] - - where - - query: path to a file containing a single SPARQL query - - ontology: one or more ontology files - - """ - - if (args.length < 2) { - println(help) - sys.exit; - } - - val queryPath = new File(args(0)) - val ontoPaths = args.drop(1).map(new File(_)) - - if (!queryPath.isFile || !ontoPaths.forall(_.isFile)) { - println("The provided arguments are not regular files.\n\n") - println(help) - sys.exit; - } + val config = RSAConfig.parse(args.toList) - val ontology = RSAOntology(ontoPaths: _*) + val ontology = + RSAOntology(config('ontology).get[File], config('data).get[List[File]]: _*) if (ontology.isRSA) { Logger print "Ontology is RSA!" - val query = RDFoxUtil.loadQueryFromFile(queryPath.getAbsoluteFile) - - ConjunctiveQuery.parse(query) match { - case Some(query) => { - val answers = ontology ask query - Logger.print(s"$answers", Logger.QUIET) - Logger print s"Number of answers: ${answers.length} (${answers.lengthWithMultiplicity})" - - /* Additional DEBUG information */ - if (Logger.level >= Logger.DEBUG) { - /* Unfiltered rules */ - val unfiltered = ontology askUnfiltered query - unfiltered map { u => - Logger print s"Number of unfiltered answers: ${u.length} (${u.map(_._1).sum})." - - /* Spurious answers */ - val spurious = { - val variables = query.variables.length - val sp = RDFoxUtil.buildDescriptionQuery("SP", variables) - ontology.queryDataStore(query, sp, RSA.Prefixes) - } - spurious map { s => - Logger print s"Number of spurious answers: ${s.length} (${s.map(_._1).sum})" - - /* Spurious/unfiltered percentage */ - val perc = - if (u.length > 0) (s.length / u.length.toFloat) * 100 else 0 - Logger print s"Percentage of spurious answers: $perc%" - } - } + if (!config('rsacheckonly).get[Boolean]) { + val query = + RDFoxUtil.loadQueryFromFile(config('query).get[File].getAbsoluteFile) + + ConjunctiveQuery.parse(query) match { + case Some(query) => { + val answers = ontology ask query + Logger.print(s"$answers", Logger.QUIET) + Logger print s"Number of answers: ${answers.length} (${answers.lengthWithMultiplicity})" + + // /* Additional DEBUG information */ + // if (Logger.level >= Logger.DEBUG) { + // /* Unfiltered rules */ + // val unfiltered = ontology askUnfiltered query + // unfiltered map { u => + // Logger print s"Number of unfiltered answers: ${u.length} (${u.map(_._1).sum})." + + // /* Spurious answers */ + // val spurious = { + // val variables = query.variables.length + // val sp = RDFoxUtil.buildDescriptionQuery("SP", variables) + // ontology.queryDataStore(query, sp, RSA.Prefixes) + // } + // spurious map { s => + // Logger print s"Number of spurious answers: ${s.length} (${s.map(_._1).sum})" + + // /* Spurious/unfiltered percentage */ + // val perc = + // if (u.length > 0) (s.length / u.length.toFloat) * 100 else 0 + // Logger print s"Percentage of spurious answers: $perc%" + // } + // } + // } } + case None => + throw new RuntimeException("Submitted query is not conjunctive") } - case None => - throw new RuntimeException("Submitted query is not conjunctive") } + } else { + + Logger print "Ontology is not RSA!" + } } -- cgit v1.2.3