[Mulgara-svn] r1624 - in branches/consistency/src/jar: content-rlog content-rlog/java/org/mulgara/content/rlog content-rlog/java/org/mulgara/krule/rlog/ast/output content-rlog/java/org/mulgara/krule/rlog/parser resolver/java/org/mulgara/resolver
pag at mulgara.org
pag at mulgara.org
Tue Mar 24 01:11:35 UTC 2009
Author: pag
Date: 2009-03-23 18:11:33 -0700 (Mon, 23 Mar 2009)
New Revision: 1624
Added:
branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogStructure.java
Modified:
branches/consistency/src/jar/content-rlog/build.xml
branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogContentHandler.java
branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogStatements.java
branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/AxiomGenerator.java
branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/RuleGenerator.java
branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/TripleGenerator.java
branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/parser/NSUtils.java
branches/consistency/src/jar/resolver/java/org/mulgara/resolver/ExportOperation.java
Log:
Now exporting RLog data to RL files
Modified: branches/consistency/src/jar/content-rlog/build.xml
===================================================================
--- branches/consistency/src/jar/content-rlog/build.xml 2009-03-24 01:10:35 UTC (rev 1623)
+++ branches/consistency/src/jar/content-rlog/build.xml 2009-03-24 01:11:33 UTC (rev 1624)
@@ -60,7 +60,7 @@
</target>
<target name="content-rlog-compile"
- depends="-content-rlog-prepare, gen-rlog-parser, resolver-spi-jar, resolver-file-jar, krule-jar"
+ depends="-content-rlog-prepare, gen-rlog-parser, resolver-spi-jar, resolver-file-jar"
description="Compiles all content-rlog related files included generated source code">
<javac destdir="${content-rlog.obj.dir}/classes" debug="on" deprecation="on" source="1.5" encoding="UTF-8">
<classpath refid="content-rlog-classpath"/>
Modified: branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogContentHandler.java
===================================================================
--- branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogContentHandler.java 2009-03-24 01:10:35 UTC (rev 1623)
+++ branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogContentHandler.java 2009-03-24 01:11:33 UTC (rev 1624)
@@ -18,6 +18,10 @@
package org.mulgara.content.rlog;
// Java 2 enterprise packages
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
@@ -94,6 +98,14 @@
*/
public void serialize(Statements statements, Content content, ResolverSession resolverSession)
throws ContentHandlerException, ModifiedException {
- throw new UnsupportedOperationException();
+ try {
+ Writer out = new BufferedWriter(new OutputStreamWriter(content.newOutputStream(), "utf-8"));
+ RlogStructure struct = new RlogStructure(resolverSession);
+ struct.load(statements);
+ struct.write(out);
+ out.close();
+ } catch (Exception e) {
+ throw new ContentHandlerException("Failed to serialize RLog to " + content.getURIString(), e);
+ }
}
}
Modified: branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogStatements.java
===================================================================
--- branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogStatements.java 2009-03-24 01:10:35 UTC (rev 1623)
+++ branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogStatements.java 2009-03-24 01:11:33 UTC (rev 1624)
@@ -54,7 +54,7 @@
/**
* Parses an {@link InputStream} into {@link Statements}.
* This parser uses memory and does not stream.
- *
+ *
* @created Feb 24, 2009
* @author Paul Gearon
* @copyright © 2008 <a href="http://www.fedora-commons.org/">Fedora Commons</a>
Added: branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogStructure.java
===================================================================
--- branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogStructure.java (rev 0)
+++ branches/consistency/src/jar/content-rlog/java/org/mulgara/content/rlog/RlogStructure.java 2009-03-24 01:11:33 UTC (rev 1624)
@@ -0,0 +1,853 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.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.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.content.rlog;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.mulgara.krule.rlog.parser.NSUtils;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.rdf.Krule;
+import org.mulgara.query.rdf.URIReferenceImpl;
+import org.mulgara.resolver.spi.GlobalizeException;
+import org.mulgara.resolver.spi.LocalizeException;
+import org.mulgara.resolver.spi.ResolverSession;
+import org.mulgara.resolver.spi.Statements;
+import org.mulgara.util.functional.Pair;
+
+import org.apache.log4j.Logger;
+import org.jrdf.graph.Literal;
+import org.jrdf.graph.Node;
+import org.jrdf.graph.URIReference;
+import org.jrdf.vocabulary.RDF;
+
+/**
+ * This class constructs an RLog structure out of a set of Statements.
+ *
+ * @created Mar 18, 2009
+ * @author Paul Gearon
+ * @copyright © 2009 <a href="http://www.fedora-commons.org/">Fedora Commons</a>
+ */
+public class RlogStructure {
+
+ /** Logger. */
+ private static Logger logger = Logger.getLogger(RlogStructure.class.getName());
+
+ /** The rdf:type URI. */
+ private static final URIReference TYPE = new URIReferenceImpl(RDF.TYPE);
+
+ /** The rdf:value URI. */
+ private static final URIReference RDF_VALUE = new URIReferenceImpl(RDF.VALUE);
+
+ /** The rdf:Seq URI. */
+ private static final URIReference RDF_SEQ = new URIReferenceImpl(RDF.SEQ);
+
+ /** The domain for system graphs. */
+ private static final String SYS = "sys";
+
+ /** The session to use for localizing and globalizing. */
+ ResolverSession session;
+
+ /** The graph to store the statements in. */
+ Map<Node,Map<URIReference,Set<Node>>> graph = new HashMap<Node,Map<URIReference,Set<Node>>>();
+
+ /** Stores all the nodes of a particular type in a single set, one for each type. */
+ Map<Node,Set<Node>> nodesByType = new HashMap<Node,Set<Node>>();
+
+ /** Maps nodes to their type */
+ Map<Node,Node> typeByNode = new HashMap<Node,Node>();
+
+ /** Maps variables to their names */
+ Map<Node,String> nameByVar = new HashMap<Node,String>();
+
+ /** Maps namesto their variables */
+ Map<String,Node> varByName = new HashMap<String,Node>();
+
+ /** Maps all the in-use namespaces to their shorthand prefixes. */
+ Map<String,String> namespaces;
+
+ /** Default map of namespaces to their shorthand prefixes. */
+ Map<String,String> defaultNamespaces;
+
+ /** A generator for new namespace names. */
+ NamespaceGenerator namespaceGen = new NamespaceGenerator();
+
+ /** The current constraint context when writing a rule. */
+ Node currentRootConstraint = null;
+
+ /** A list of the rdf:_x IDs used for sequences. */
+ List<URIReference> listIds = new ArrayList<URIReference>();
+
+ /** The local node for the rdf:type URI. */
+ final long rdfType;
+
+
+ /**
+ * Constructs the structure, along with the session used to help build it.
+ * @param session The mechanism for convergins local nodes to global, and back.
+ * @throws LocalizeException If a global node could not be localized to a long.
+ */
+ public RlogStructure(ResolverSession session) throws LocalizeException {
+ this.session = session;
+ rdfType = session.localize(TYPE);
+ initNamespaces();
+ }
+
+
+ /**
+ * Initialized the namespaces with the registered domains.
+ */
+ private void initNamespaces() {
+ Map<String,String> ns = new HashMap<String,String>();
+ for (Map.Entry<String,String> e: NSUtils.getRegisteredDomains()) {
+ ns.put(e.getValue(), e.getKey());
+ }
+ defaultNamespaces = Collections.unmodifiableMap(ns);
+ namespaces = new HashMap<String,String>();
+ // add in sys: so it does not get mapped
+ namespaces.put(SYS + ":", SYS);
+ }
+
+
+ /**
+ * Build a structure in memory to represent the Krule data structure.
+ * @param statements The statements to load.
+ * @throws TuplesException If there was a problem accessing the statements.
+ * @throws GlobalizeException If there was a problem converting the statements to references.
+ */
+ public void load(Statements statements) throws TuplesException, GlobalizeException {
+ statements.beforeFirst();
+ while (statements.next()) {
+ long subject = statements.getSubject();
+ long predicate = statements.getPredicate();
+ long obj = statements.getObject();
+
+ if (predicate == rdfType) {
+ addType(subject, obj);
+ } else {
+ addToGraph(subject, predicate, obj);
+ }
+ }
+ nameVariables();
+ }
+
+
+ /**
+ * For every variable that was found, map it to its name.
+ */
+ void nameVariables() {
+ Set<Node> vars = nodesByType.get(Krule.VARIABLE);
+ if (vars == null) return;
+ for (Node v: vars) {
+ Node name = getPropertyValue(v, Krule.NAME);
+ if (!(name instanceof Literal)) throw new IllegalArgumentException("Bad Krule structure. Variable name is not a string.");
+ String sName = getValidVariableName((Literal)name);
+ nameByVar.put(v, sName);
+ varByName.put(sName, v);
+ }
+ }
+
+
+ /**
+ * Write a set of statements representing RLog to a given writer.
+ * @param writer The output to send the RLog to.
+ * @throws IOException If the data could not be converted or written out.
+ */
+ public void write(Writer writer) throws IOException {
+ if (writer == null) throw new IllegalArgumentException("Writer cannot be null.");
+
+ StringWriter out = new StringWriter();
+ writeAxioms(out);
+ writeChecks(out);
+ writeRules(out);
+ out.close();
+
+ writePrefixes(writer);
+ writer.append(out.getBuffer());
+ }
+
+
+ /**
+ * Sets the type for an object.
+ * @param s The subject to be typed.
+ * @param t The type of the subject.
+ * @throws GlobalizeException If the subject or type could not be globalized.
+ */
+ void addType(long s, long t) throws GlobalizeException {
+ Node subj = session.globalize(s);
+ Node type = session.globalize(t);
+ // map the type to the node
+ addValue(nodesByType, type, subj);
+ // map the node to its type
+ typeByNode.put(subj, type);
+ }
+
+
+ /**
+ * Add a triple to the graph.
+ * @param s The subject of the triple.
+ * @param p The predicate of the triple.
+ * @param o The object of the triple.
+ * @throws GlobalizeException If one of the elements of the triple could not be
+ * converted to a global node.
+ */
+ void addToGraph(long s, long p, long o) throws GlobalizeException {
+ Node subj = session.globalize(s);
+ URIReference pred = (URIReference)session.globalize(p);
+ Node obj = session.globalize(o);
+ addPropertyValue(graph, subj, pred, obj);
+ }
+
+
+ /**
+ * Writes all the axioms to the output as horn clauses.
+ * @param out The writer to send the RLog to.
+ * @throws IOException If there was an error writing to the output.
+ */
+ void writePrefixes(Writer out) throws IOException {
+ for (Map.Entry<String,String> ns: namespaces.entrySet()) {
+ String k = ns.getKey();
+ String v = ns.getValue() + ":";
+ if (v.equals(k)) continue;
+ out.append("@prefix ");
+ out.append(v);
+ out.append(" <");
+ out.append(k);
+ out.append("> .\n");
+ }
+ out.append("\n");
+ }
+
+
+ /**
+ * Writes all the axioms to the output as horn clauses.
+ * @param out The writer to send the RLog to.
+ * @throws IOException If there was an error writing to the output.
+ */
+ void writeAxioms(Writer out) throws IOException {
+ Set<Node> axioms = nodesByType.get(Krule.AXIOM);
+ if (axioms == null) return;
+ for (Node axiom: axioms) {
+ Map<URIReference,Set<Node>> properties = graph.get(axiom);
+ Node s = getSingle(properties, Krule.AXIOM_SUBJECT);
+ Node p = getSingle(properties, Krule.AXIOM_PREDICATE);
+ Node o = getSingle(properties, Krule.AXIOM_OBJECT);
+ out.append(toPredicate(s, p, o));
+ out.append(".\n");
+ }
+ out.append("\n");
+ }
+
+
+ /**
+ * Writes all the consistency checks to the output as horn clauses.
+ * @param out The writer to send the RLog to.
+ * @throws IOException If there was an error writing to the output.
+ */
+ void writeChecks(Writer out) throws IOException {
+ Set<Node> checks = nodesByType.get(Krule.CHECK);
+ if (checks == null) return;
+ for (Node check: checks) {
+ Map<URIReference,Set<Node>> properties = graph.get(check);
+ Node q = getSingle(properties, Krule.HAS_QUERY);
+ Node qType = typeByNode.get(q);
+ if (!qType.equals(Krule.QUERY)) {
+ throw new IllegalArgumentException("Bad Krule structure. Consistency check has a query that has a non-query type: " + qType);
+ }
+ out.append(":- ");
+ writeBody(out, q);
+ out.append(".\n");
+ }
+ out.append("\n");
+ }
+
+
+ /**
+ * Writes all the rules to the output as horn clauses.
+ * @param out The writer to send the RLog to.
+ * @throws IOException If there was an error writing to the output.
+ */
+ void writeRules(Writer out) throws IOException {
+ Set<Node> rules = nodesByType.get(Krule.RULE);
+ if (rules == null) return;
+ for (Node rule: rules) {
+ Node q = getPropertyValue(rule, Krule.HAS_QUERY);
+ Node qType = typeByNode.get(q);
+ if (!qType.equals(Krule.QUERY)) {
+ throw new IllegalArgumentException("Bad Krule structure. Consistency check has a query that has a non-query type: " + qType);
+ }
+ writeHead(out, q);
+ out.append(" :- ");
+ writeBody(out, q);
+ out.append(".\n");
+ }
+ out.append("\n");
+ }
+
+
+ /**
+ * Writes out the head of a query associated with a rule.
+ * @param out The writer output.
+ * @param query The node representing the query.
+ */
+ void writeHead(Writer out, Node query) throws IOException {
+ Node seq = getPropertyValue(query, Krule.SELECTION_VARS);
+ Node sType = typeByNode.get(seq);
+ if (!sType.equals(RDF_SEQ)) {
+ throw new IllegalArgumentException("Bad Krule structure. Query selection sequence is not a sequence type: " + sType);
+ }
+
+ // loop over multiple triples
+ int seqNr = 1;
+ Node s;
+ while (null != (s = getPropertyValue(seq, getListId(seqNr++)))) {
+ Node p = getPropertyValue(seq, getListId(seqNr++));
+ Node o = getPropertyValue(seq, getListId(seqNr++));
+ if (p == null || o == null) throw new IllegalArgumentException("Bad Krule structure. Query selection sequence is not set of triples. " + seqNr + " elements");
+ // separate triples with commas
+ if (seqNr > 4) out.append(", ");
+ out.append(toPredicate(s, p, o));
+ }
+ }
+
+
+ /**
+ * Writes out the body (WHERE clause) of a query associated with a rule.
+ * @param out The writer output.
+ * @param query The node representing the query.
+ */
+ void writeBody(Writer out, Node query) throws IOException {
+ Node constraint = getPropertyValue(query, Krule.HAS_WHERE_CLAUSE);
+ // remember the current context in case it is needed
+ currentRootConstraint = constraint;
+ writeConstraint(out, constraint, false);
+ }
+
+
+ /**
+ * Writes a general constraint type that may be inverted. This method is recursive.
+ * @param out The writer output.
+ * @param constraint The constraint to be written.
+ * Accepts conjunctions, differences, transitive and simple constraints.
+ * @param inv Indicates that the constraint is inverted.
+ * @throws IOException Due to a write error on the writer.
+ */
+ void writeConstraint(Writer out, Node constraint, boolean inv) throws IOException {
+ Node cType = typeByNode.get(constraint);
+ if (cType.equals(Krule.CONSTRAINT_CONJUNCTION)) {
+ writeConstraintConjunction(out, constraint, inv);
+ } else if (cType.equals(Krule.SIMPLE_CONSTRAINT)) {
+ writeConstraintSimple(out, constraint, inv);
+ } else if (cType.equals(Krule.DIFFERENCE)) {
+ writeConstraintDifference(out, constraint, inv);
+ } else if (cType.equals(Krule.TRANSITIVE_CONSTRAINT)) {
+ writeConstraintTransitive(out, constraint, inv);
+ } else {
+ throw new IllegalArgumentException("Bad Krule structure. Unsupported Constraint type: " + cType);
+ }
+ }
+
+
+ /**
+ * Writes the simple constraint type. This is just a triple.
+ * @param out The writer output.
+ * @param constraint The constraint to be written.
+ * @param inv Indicates that the constraint is inverted.
+ * @throws IOException Due to a write error on the writer.
+ */
+ void writeConstraintSimple(Writer out, Node constraint, boolean inv) throws IOException {
+ Node s = getPropertyValue(constraint, Krule.HAS_SUBJECT);
+ Node p = getPropertyValue(constraint, Krule.HAS_PREDICATE);
+ Node o = getPropertyValue(constraint, Krule.HAS_OBJECT);
+ // throw away the graph, as this is autodetected from the predicate in RLog parsing
+ if (s == null || p == null || o == null) {
+ throw new IllegalArgumentException("Bad Krule structure. Incomplete constraint.");
+ }
+ if (inv) out.append("~");
+ out.append(toPredicate(s, p, o));
+ }
+
+
+ /**
+ * Writes a constraint conjunction.
+ * @param out The writer output.
+ * @param constraint The constraint to be written.
+ * @param inv Indicates that the constraint is inverted.
+ * @throws IOException Due to a write error on the writer.
+ */
+ void writeConstraintConjunction(Writer out, Node constraint, boolean inv) throws IOException {
+ Map<URIReference,Set<Node>> constraintProps = graph.get(constraint);
+ if (constraintProps == null) throw new IllegalArgumentException("Bad Krule structure. Missing arguments for a conjunction.");
+ Set<Node> args = constraintProps.get(Krule.ARGUMENT);
+ // go through all the constraints, separating them with commas
+ boolean first = true;
+ for (Node c: args) {
+ if (first) first = false;
+ else out.append(", ");
+ writeConstraint(out, c, inv);
+ }
+ }
+
+
+ /**
+ * Writes a difference constraint.
+ * @param out The writer output.
+ * @param constraint The constraint to be written.
+ * @param inv Indicates that the constraint is inverted.
+ * @throws IOException Due to a write error on the writer.
+ */
+ void writeConstraintDifference(Writer out, Node constraint, boolean inv) throws IOException {
+ Node minuend = getPropertyValue(constraint, Krule.MINUEND);
+ Node subtrahend = getPropertyValue(constraint, Krule.SUBTRAHEND);
+ if (minuend == null) throw new IllegalArgumentException("Bad Krule structure. Missing minuend on a Difference.");
+ if (subtrahend == null) throw new IllegalArgumentException("Bad Krule structure. Missing subtrahend on a Difference.");
+ writeConstraint(out, minuend, inv);
+ out.append(", ");
+ writeConstraint(out, subtrahend, !inv);
+ }
+
+
+ /**
+ * Writes a transitive constraint.
+ * @param out The writer output.
+ * @param constraint The constraint to be written.
+ * @param inv Indicates that the constraint is inverted.
+ * @throws IOException Due to a write error on the writer.
+ */
+ void writeConstraintTransitive(Writer out, Node constraint, boolean inv) throws IOException {
+ Node arg = getPropertyValue(constraint, Krule.TRANSITIVE_ARGUMENT);
+ if (arg == null || !arg.equals(Krule.SIMPLE_CONSTRAINT)) {
+ throw new IllegalArgumentException("Bad Krule structure. Transitive constraints must operate on simple arguments.");
+ }
+ Node s = getPropertyValue(arg, Krule.HAS_SUBJECT);
+ Node p = getPropertyValue(arg, Krule.HAS_PREDICATE);
+ Node o = getPropertyValue(arg, Krule.HAS_OBJECT);
+ // throw away the graph, as this is autodetected from the predicate in RLog parsing
+ if (s == null || p == null || o == null) {
+ throw new IllegalArgumentException("Bad Krule structure. Incomplete constraint in transitive constraint.");
+ }
+
+ Node newVar = getUnusedVar();
+ out.append(toPredicate(s, p, newVar));
+ out.append(", ");
+ out.append(toPredicate(newVar, p, o));
+ }
+
+
+ /**
+ * Finds a variable that is not in use in the current constraint.
+ * @return A variable this is not being used in the current rule.
+ */
+ Node getUnusedVar() {
+ for (char v = 'A'; v <= 'Z'; v++) {
+ Node var = varByName.get(Character.toString(v));
+ if (var != null) return var;
+ }
+ // every variable is in use somewhere. Have to search the current rule.
+ Set<Node> currentVariables = getVariables(currentRootConstraint);
+ for (Node var: nameByVar.keySet()) {
+ if (!currentVariables.contains(var)) return var;
+ }
+ throw new IllegalStateException("Rule is too complex. It contains too many variables.");
+ }
+
+
+ /**
+ * Accumulates all of the variables under a given node.
+ * @param constraint The constraint node to find variables under.
+ * @return A Set of nodes which represent variables.
+ */
+ Set<Node> getVariables(Node constraint) {
+ Node type = typeByNode.get(constraint);
+ if (type.equals(Krule.SIMPLE_CONSTRAINT)) {
+ return getVariablesSimple(constraint);
+ } else if (type.equals(Krule.CONSTRAINT_CONJUNCTION)) {
+ return getVariablesConjunction(constraint);
+ } else if (type.equals(Krule.DIFFERENCE)) {
+ return getVariablesDifference(constraint);
+ } else if (type.equals(Krule.TRANSITIVE_CONSTRAINT)) {
+ return getVariablesTransitive(constraint);
+ } else {
+ throw new IllegalArgumentException("Bad Krule structure. Unsupported Constraint type: " + type);
+ }
+ }
+
+
+ /**
+ * Accumulates all of the variables in a simple constraint.
+ * @param constraint The constraint node to find variables under.
+ * @return A Set of nodes which represent variables.
+ */
+ Set<Node> getVariablesSimple(Node constraint) {
+ Node s = getPropertyValue(constraint, Krule.HAS_SUBJECT);
+ Node p = getPropertyValue(constraint, Krule.HAS_PREDICATE);
+ Node o = getPropertyValue(constraint, Krule.HAS_OBJECT);
+ if (s == null || p == null || o == null) {
+ throw new IllegalArgumentException("Bad Krule structure. Incomplete constraint.");
+ }
+ Set<Node> vars = new HashSet<Node>();
+ if (nameByVar.containsKey(s)) vars.add(s);
+ if (nameByVar.containsKey(p)) vars.add(p);
+ if (nameByVar.containsKey(o)) vars.add(o);
+ return vars;
+ }
+
+
+ /**
+ * Accumulates all of the variables in a conjunction.
+ * @param constraint The constraint node to find variables under.
+ * @return A Set of nodes which represent variables.
+ */
+ Set<Node> getVariablesConjunction(Node constraint) {
+ // Recursively get the variables from the arguments
+ Map<URIReference,Set<Node>> constraintProps = graph.get(constraint);
+ if (constraintProps == null) throw new IllegalArgumentException("Bad Krule structure. Missing arguments for a conjunction.");
+ Set<Node> args = constraintProps.get(Krule.ARGUMENT);
+ // accumulate the variables into the first result. This is not functional, but more efficient.
+ Set<Node> vars = null;
+ for (Node c: args) {
+ Set<Node> tmp = getVariables(c);
+ if (vars == null) vars = tmp;
+ else vars.addAll(tmp);
+ }
+ return vars;
+ }
+
+
+ /**
+ * Accumulates all of the variables in a difference.
+ * @param constraint The constraint node to find variables under.
+ * @return A Set of nodes which represent variables.
+ */
+ Set<Node> getVariablesDifference(Node constraint) {
+ // Recursively get the variables from the arguments
+ Node minuend = getPropertyValue(constraint, Krule.MINUEND);
+ Node subtrahend = getPropertyValue(constraint, Krule.SUBTRAHEND);
+ if (minuend == null) throw new IllegalArgumentException("Bad Krule structure. Missing minuend on a Difference.");
+ if (subtrahend == null) throw new IllegalArgumentException("Bad Krule structure. Missing subtrahend on a Difference.");
+ Set<Node> vars = getVariables(minuend);
+ vars.addAll(getVariables(subtrahend)); // not quite functional, but more efficient
+ return vars;
+ }
+
+
+ /**
+ * Accumulates all of the variables in a transitive constraint.
+ * @param constraint The constraint node to find variables under.
+ * @return A Set of nodes which represent variables.
+ */
+ Set<Node> getVariablesTransitive(Node constraint) {
+ // Recursively get the variables from the arguments
+ Node arg = getPropertyValue(constraint, Krule.TRANSITIVE_ARGUMENT);
+ if (arg == null || !arg.equals(Krule.SIMPLE_CONSTRAINT)) {
+ throw new IllegalArgumentException("Bad Krule structure. Transitive constraints must operate on simple arguments.");
+ }
+ return getVariables(arg);
+ }
+
+
+ /**
+ * Converts a triple to a string containing a DL predicate.
+ * @param s The subject of the triple.
+ * @param p The predicate of the triple.
+ * @param o The object of the triple.
+ * @return A string with the DL version of the predicate.
+ */
+ String toPredicate(Node s, Node p, Node o) {
+ if (isType(p)) return toTypePredicate(s, o);
+ return toBinaryPredicate(s, p, o);
+ }
+
+
+ /**
+ * Convert a subject and type into a Type predicate.
+ * @param s The subject to be typed.
+ * @param type The type of the subject.
+ * @return A string with the subject and type.
+ */
+ String toTypePredicate(Node s, Node type) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(toString(type));
+ sb.append("(");
+ sb.append(toString(s));
+ sb.append(")");
+ return sb.toString();
+ }
+
+
+ /**
+ * Convert a triple into a binary predicate.
+ * @param s The subject of the triple.
+ * @param p The predicate of the triple.
+ * @param o The object of the triple.
+ * @return A string with the DL version of the binary predicate.
+ */
+ String toBinaryPredicate(Node s, Node p, Node o) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(toString(p));
+ sb.append("(");
+ sb.append(toString(s));
+ sb.append(",");
+ sb.append(toString(o));
+ sb.append(")");
+ return sb.toString();
+ }
+
+
+ /**
+ * Gets the string representation of an object referenced by URIReference.
+ * @param n The node to get the value of.
+ * @return A string representation of the object.
+ */
+ String toString(Node n) {
+ Node refType = typeByNode.get(n); // Variable, URIReference or Literal
+ if (refType == null) throw new IllegalArgumentException("Bad Krule structure. No type for node: " + n);
+ if (!(refType instanceof URIReference)) throw new IllegalArgumentException("Bad Krule structure. Expected a reference for type, but got: " + refType);
+
+ // Get the referenced data
+ if (refType.equals(Krule.URI_REF)) {
+ // writing a URI
+ Node value = getPropertyValue(n, RDF_VALUE);
+ if (value == null || !(value instanceof URIReference)) throw new IllegalArgumentException("Bad Krule structure. URIReference came back with the wrong type: " + value + "(" + value.getClass().getName() + ")");
+ return namespaceString((URIReference)value);
+
+ } else if (refType.equals(Krule.VARIABLE)) {
+ return nameByVar.get(n);
+
+ } else if (refType.equals(Krule.LITERAL)) {
+ // writing a literal
+ Node value = getPropertyValue(n, RDF_VALUE);
+ if (!(value instanceof Literal)) throw new IllegalArgumentException("Bad Krule structure. Literal came back with the wrong type: " + value + "(" + value.getClass().getName() + ")");
+ return value.toString();
+
+ } else throw new IllegalArgumentException("Bad Krule structure. Output node is not a URI Reference, a variable, or a literal: " + refType);
+ }
+
+
+ /**
+ * Tests if a node is a reference to the rdf:type URI.
+ * @param n The node to check as a reference.
+ * @return <code>true</code> only if the node is a reference and it refers to rdf:type
+ */
+ boolean isType(Node n) {
+ Node refType = typeByNode.get(n); // Variable, URIReference or Literal
+ if (refType == null) throw new IllegalArgumentException("Bad Krule structure. No type for node: " + n);
+ if (!(refType instanceof URIReference)) throw new IllegalArgumentException("Bad Krule structure. Expected a reference for type, but got: " + refType);
+
+ // Get the referenced data
+ if (refType.equals(Krule.URI_REF)) {
+ // writing a URI
+ Node value = getPropertyValue(n, RDF_VALUE);
+ if (value == null || !(value instanceof URIReference)) throw new IllegalArgumentException("Bad Krule structure. URIReference came back with the wrong type: " + value + "(" + value.getClass().getName() + ")");
+ return value.equals(TYPE);
+ }
+ return false;
+ }
+
+
+ /**
+ * Get the namespace version of a URI.
+ * e.g. rdf:value instead of http://www.w3.org/1999/02/22-rdf-syntax-ns#value
+ * @param r The URI reference to convert to namespace form.
+ * @return The namespaced version of the URI.
+ */
+ String namespaceString(URIReference r) {
+ Pair<String,String> nsPair = addToNamespace(r);
+ String dom = nsPair.first();
+ String val = nsPair.second();
+
+ // Krule is the default namespace
+ if (dom.equals(Krule.KRULE)) return val;
+ return ((dom.endsWith(":")) ? dom : dom + ":") + val;
+ }
+
+
+ /**
+ * Scans nodes that are URIReferences, and adds them to the list of namespaces if not already there.
+ * @param r A node that may be a reference to be scanned.
+ */
+ void addToNamespace(Node n) {
+ if (!(n instanceof URIReference)) return;
+ addToNamespace((URIReference)n);
+ }
+
+
+ /**
+ * Scans a URIReference, and adds it to the list of namespaces if not already there.
+ * @param r The reference to be scanned.
+ * @return The domain abbreviation to use for this reference, and the value in the domain as a Pair.
+ */
+ Pair<String,String> addToNamespace(URIReference r) {
+ Pair<String,String> nsPair = splitUri(r.getURI());
+ String ns = nsPair.first();
+ String val = nsPair.second();
+ if (val.length() == 0) throw new IllegalArgumentException("Bad RLog data. URI needs a value in a domain to be serialized in RLog: " + r);
+
+ // determine the domain to use for this namespace
+ String dom = defaultNamespaces.get(ns);
+ if (dom == null) {
+ dom = namespaces.get(ns);
+ if (dom == null) {
+ namespaces.put(ns, dom = namespaceGen.newNamespace());
+ }
+ } else {
+ // domain is in the default list, add it to the in-use list
+ if (!namespaces.containsKey(ns)) namespaces.put(ns, dom);
+ }
+ return new Pair<String,String>(dom, val);
+ }
+
+
+ /**
+ * Gets the reference for a sequence member predicate.
+ * @param n The sequence index.
+ * @return The URI reference for <em>rdf:_n</em>.
+ */
+ URIReference getListId(int n) {
+ if (listIds.size() < n) {
+ for (int i = listIds.size() + 1; i <= n; i++) {
+ URI u = URI.create(RDF.BASE_URI + "_" + i);
+ listIds.add(new URIReferenceImpl(u));
+ }
+ }
+ return listIds.get(n - 1);
+ }
+
+
+ /**
+ * Convert a literal into a valid variable name. Variable names are a single upper case character.
+ * @param value The literal to convert.
+ * @return The validated, and converted name of the variable.
+ */
+ String getValidVariableName(Literal value) {
+ String var = ((Literal)value).getLexicalForm();
+ if (var.length() != 1) {
+ String v = var.substring(0, 1).toUpperCase();
+ logger.warn("Krule structure uses long variable names. Truncating: " + var + " -> " + v);
+ var = v;
+ }
+ if (!Character.isLetter(var.charAt(0))) throw new IllegalArgumentException("Bad Krule structure. Variable must be a letter: " + var);
+ if (!Character.isUpperCase(var.charAt(0))) {
+ logger.warn("Variable names must have upper case letters: " + var);
+ var = var.toUpperCase();
+ }
+ return var;
+ }
+
+
+ /**
+ * Gets the value of a property on an object.
+ * @param s The object in the graph.
+ * @param p The property being looked for.
+ * @return The value of the required property.
+ */
+ Node getPropertyValue(Node s, URIReference p) {
+ Map<URIReference,Set<Node>> values = graph.get(s);
+ if (values == null) throw new IllegalArgumentException("Bad Krule structure. Missing property <" + p + "> on object <" + s + ">");
+ return getSingle(values, p);
+ }
+
+
+ /**
+ * Map an object to a property value pair.
+ * @param subj The subject to set a property and value for.
+ * @param property The property for the subject.
+ * @param value The value for the subject's property.
+ */
+ static final void addPropertyValue(Map<Node,Map<URIReference,Set<Node>>> graph, Node subj, URIReference property, Node value) {
+ Map<URIReference,Set<Node>> propVal = graph.get(subj);
+ if (propVal == null) {
+ propVal = new HashMap<URIReference,Set<Node>>();
+ graph.put(subj, propVal);
+ }
+ addValue(propVal, property, value);
+ }
+
+
+ /**
+ * Map a property to a value.
+ * @param propertyValues The full set of properties and values for the current object.
+ * @param property The property to set on the current object.
+ * @param value The value to set the property to.
+ */
+ static final <T> void addValue(Map<T,Set<Node>> propertyValues, T property, Node value) {
+ Set<Node> values = propertyValues.get(property);
+ if (values == null) {
+ values = new HashSet<Node>();
+ propertyValues.put(property, values);
+ }
+ values.add(value);
+ }
+
+
+ /**
+ * Retrieves a single value from a multimap.
+ * @param <K> The type of the keys in the multimap.
+ * @param <V> The type of the values in the multimap.
+ * @param map The map to get the value from.
+ * @param key The key to find the value with.
+ * @return The single value found associated with the key, or null if not found.
+ * @throws IllegalArgumentException If the key maps to a set with more than one value.
+ */
+ static final <K,V> V getSingle(Map<K,Set<V>> map, K key) {
+ Set<V> vals = map.get(key);
+ if (vals == null || vals.size() == 0) return null;
+ if (vals.size() != 1) throw new IllegalArgumentException("Expecting singleton from a set of size: " + vals.size());
+ return vals.iterator().next();
+ }
+
+
+ /**
+ * Splits a URI into two sections. The second section contains the trailing identifier
+ * that includes only letters, digits and underscores. The first section is everything else.
+ * @param uri The URI to split.
+ * @return A pair of strings containing the two parts of the original URI.
+ */
+ static final Pair<String,String> splitUri(URI uri) {
+ String u = uri.toString();
+ for (int p = u.length() - 1; p >= 0; p--) {
+ char ch = u.charAt(p);
+ if (!Character.isLetterOrDigit(ch) && ch != '_' && ch != '-') {
+ p = p + 1;
+ return new Pair<String,String>(u.substring(0, p), u.substring(p));
+ }
+ }
+ return new Pair<String,String>("", u);
+ }
+
+
+ /**
+ * This class is a utility to generate new namespace names.
+ */
+ class NamespaceGenerator {
+ /** The namespace counter */
+ int n = 1;
+
+ /**
+ * Create a new name for a namespace.
+ * @return A new name.
+ */
+ String newNamespace() {
+ return "ns" + n++;
+ }
+ }
+}
Modified: branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/AxiomGenerator.java
===================================================================
--- branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/AxiomGenerator.java 2009-03-24 01:10:35 UTC (rev 1623)
+++ branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/AxiomGenerator.java 2009-03-24 01:11:33 UTC (rev 1624)
@@ -31,7 +31,7 @@
import java.util.Collection;
import java.util.List;
-import static org.mulgara.krule.KruleLoader.*;
+import static org.mulgara.query.rdf.Krule.*;
/**
* Writes variables to a list of triples.
Modified: branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/RuleGenerator.java
===================================================================
--- branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/RuleGenerator.java 2009-03-24 01:10:35 UTC (rev 1623)
+++ branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/RuleGenerator.java 2009-03-24 01:11:33 UTC (rev 1624)
@@ -38,25 +38,25 @@
import java.util.Collections;
import java.util.List;
-import static org.mulgara.krule.KruleLoader.ARGUMENT;
-import static org.mulgara.krule.KruleLoader.CHECK;
-import static org.mulgara.krule.KruleLoader.CONSTRAINT_CONJUNCTION;
-import static org.mulgara.krule.KruleLoader.DIFFERENCE;
-import static org.mulgara.krule.KruleLoader.HAS_QUERY;
-import static org.mulgara.krule.KruleLoader.HAS_WHERE_CLAUSE;
-import static org.mulgara.krule.KruleLoader.HAS_SUBJECT;
-import static org.mulgara.krule.KruleLoader.HAS_PREDICATE;
-import static org.mulgara.krule.KruleLoader.HAS_OBJECT;
-import static org.mulgara.krule.KruleLoader.HAS_GRAPH;
-import static org.mulgara.krule.KruleLoader.MINUEND;
-import static org.mulgara.krule.KruleLoader.NAME;
-import static org.mulgara.krule.KruleLoader.QUERY;
-import static org.mulgara.krule.KruleLoader.RULE;
-import static org.mulgara.krule.KruleLoader.SELECTION_VARS;
-import static org.mulgara.krule.KruleLoader.SIMPLE_CONSTRAINT;
-import static org.mulgara.krule.KruleLoader.SUBTRAHEND;
-import static org.mulgara.krule.KruleLoader.TRIGGERS;
-import static org.mulgara.krule.KruleLoader.VARIABLE;
+import static org.mulgara.query.rdf.Krule.ARGUMENT;
+import static org.mulgara.query.rdf.Krule.CHECK;
+import static org.mulgara.query.rdf.Krule.CONSTRAINT_CONJUNCTION;
+import static org.mulgara.query.rdf.Krule.DIFFERENCE;
+import static org.mulgara.query.rdf.Krule.HAS_QUERY;
+import static org.mulgara.query.rdf.Krule.HAS_WHERE_CLAUSE;
+import static org.mulgara.query.rdf.Krule.HAS_SUBJECT;
+import static org.mulgara.query.rdf.Krule.HAS_PREDICATE;
+import static org.mulgara.query.rdf.Krule.HAS_OBJECT;
+import static org.mulgara.query.rdf.Krule.HAS_GRAPH;
+import static org.mulgara.query.rdf.Krule.MINUEND;
+import static org.mulgara.query.rdf.Krule.NAME;
+import static org.mulgara.query.rdf.Krule.QUERY;
+import static org.mulgara.query.rdf.Krule.RULE;
+import static org.mulgara.query.rdf.Krule.SELECTION_VARS;
+import static org.mulgara.query.rdf.Krule.SIMPLE_CONSTRAINT;
+import static org.mulgara.query.rdf.Krule.SUBTRAHEND;
+import static org.mulgara.query.rdf.Krule.TRIGGERS;
+import static org.mulgara.query.rdf.Krule.VARIABLE;
/**
* Writes rules to a list of triples.
Modified: branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/TripleGenerator.java
===================================================================
--- branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/TripleGenerator.java 2009-03-24 01:10:35 UTC (rev 1623)
+++ branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/TripleGenerator.java 2009-03-24 01:11:33 UTC (rev 1624)
@@ -16,9 +16,9 @@
package org.mulgara.krule.rlog.ast.output;
-import static org.mulgara.krule.KruleLoader.KRULE;
-import static org.mulgara.krule.KruleLoader.LITERAL;
-import static org.mulgara.krule.KruleLoader.URI_REF;
+import static org.mulgara.query.rdf.Krule.KRULE;
+import static org.mulgara.query.rdf.Krule.LITERAL;
+import static org.mulgara.query.rdf.Krule.URI_REF;
import java.net.URI;
import java.net.URISyntaxException;
Modified: branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/parser/NSUtils.java
===================================================================
--- branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/parser/NSUtils.java 2009-03-24 01:10:35 UTC (rev 1623)
+++ branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/parser/NSUtils.java 2009-03-24 01:11:33 UTC (rev 1624)
@@ -18,8 +18,10 @@
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import org.mulgara.krule.rlog.rdf.RDF;
@@ -130,4 +132,13 @@
public static String getRegisteredNamespace(String domain) {
return registeredDomains.get(domain);
}
+
+
+ /**
+ * Returns a list of entries in the registered domains.
+ * @return A Set of Map.Entries which map domain abbreviations to full namespaces.
+ */
+ public static Set<Map.Entry<String,String>> getRegisteredDomains() {
+ return Collections.unmodifiableSet(registeredDomains.entrySet());
+ }
}
Modified: branches/consistency/src/jar/resolver/java/org/mulgara/resolver/ExportOperation.java
===================================================================
--- branches/consistency/src/jar/resolver/java/org/mulgara/resolver/ExportOperation.java 2009-03-24 01:10:35 UTC (rev 1623)
+++ branches/consistency/src/jar/resolver/java/org/mulgara/resolver/ExportOperation.java 2009-03-24 01:11:33 UTC (rev 1624)
@@ -17,6 +17,7 @@
import java.util.Map;
import org.mulgara.content.rdfxml.writer.RDFXMLWriter;
+import org.mulgara.content.rlog.RlogStructure;
import org.mulgara.content.n3.N3Writer;
import org.mulgara.query.Constraint;
import org.mulgara.query.ConstraintImpl;
@@ -108,6 +109,10 @@
if (path != null && (path.endsWith(".n3") || path.endsWith(".nt") || path.endsWith(".ttl"))) {
N3Writer n3Writer = new N3Writer();
n3Writer.write(graphStatements, systemResolver, writer);
+ } else if (path != null && (path.endsWith(".rl") || path.endsWith(".dl") || path.endsWith(".rlog"))) {
+ RlogStructure struct = new RlogStructure(systemResolver);
+ struct.load(graphStatements);
+ struct.write(writer);
} else {
RDFXMLWriter rdfWriter = new RDFXMLWriter();
rdfWriter.write(graphStatements, systemResolver, writer, prefixes);
More information about the Mulgara-svn
mailing list