[Mulgara-svn] r1621 - in branches/consistency/src/jar: content-rlog/java/org/mulgara/krule/rlog/ast/output krule/java/org/mulgara/krule
pag at mulgara.org
pag at mulgara.org
Wed Mar 18 22:24:11 UTC 2009
Author: pag
Date: 2009-03-18 15:24:10 -0700 (Wed, 18 Mar 2009)
New Revision: 1621
Added:
branches/consistency/src/jar/krule/java/org/mulgara/krule/ConsistencyCheck.java
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/RuleWriter.java
branches/consistency/src/jar/krule/java/org/mulgara/krule/KruleLoader.java
branches/consistency/src/jar/krule/java/org/mulgara/krule/QueryStruct.java
branches/consistency/src/jar/krule/java/org/mulgara/krule/Rule.java
Log:
Now writing ConsistencyChecks as a new rule type, and loading them up with the KruleLoader to be run with the rules
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-17 19:54:23 UTC (rev 1620)
+++ branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/RuleGenerator.java 2009-03-18 22:24:10 UTC (rev 1621)
@@ -18,6 +18,7 @@
import org.jrdf.vocabulary.RDF;
import org.mulgara.krule.rlog.ParseException;
+import org.mulgara.krule.rlog.ast.CheckRule;
import org.mulgara.krule.rlog.ast.Predicate;
import org.mulgara.krule.rlog.ast.Rule;
import org.mulgara.krule.rlog.parser.URIParseException;
@@ -34,9 +35,11 @@
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
+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;
@@ -45,11 +48,13 @@
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;
@@ -71,6 +76,9 @@
/** The node for the krule:Rule type */
private final long kruleRule;
+ /** The node for the krule:Check type */
+ private final long kruleCheck;
+
/** The node for the krule:Query type */
private final long kruleQuery;
@@ -113,6 +121,12 @@
/** The node for the krule:argument predicate */
private final long kruleArgument;
+ /** The node for the krule:minuend predicate */
+ private final long kruleMinuend;
+
+ /** The node for the krule:subtrahend predicate */
+ private final long kruleSubtrahend;
+
/** The node for the krule:name predicate */
private final long kruleName;
@@ -129,6 +143,7 @@
this.rules = rules;
rdfSeq = resolverSession.localize(new URIReferenceImpl(RDF.SEQ));
kruleRule = resolverSession.localize(RULE);
+ kruleCheck = resolverSession.localize(CHECK);
kruleQuery = resolverSession.localize(QUERY);
kruleDifference = resolverSession.localize(DIFFERENCE);
kruleConjunction = resolverSession.localize(CONSTRAINT_CONJUNCTION);
@@ -143,6 +158,8 @@
kruleSelVars = resolverSession.localize(SELECTION_VARS);
kruleHasWhereClause = resolverSession.localize(HAS_WHERE_CLAUSE);
kruleArgument = resolverSession.localize(ARGUMENT);
+ kruleMinuend = resolverSession.localize(MINUEND);
+ kruleSubtrahend = resolverSession.localize(SUBTRAHEND);
kruleName = resolverSession.localize(NAME);
initSeqTo(3);
}
@@ -180,18 +197,24 @@
private List<long[]> emitRule(List<long[]> triples, Rule rule) throws NodePoolException, ParseException, LocalizeException, URISyntaxException, URIParseException {
long ruleNode = toKruleNode(rule.getName());
- // rule rdf:type kruleRule
- add(triples, ruleNode, rdfType, kruleRule);
+ if (rule instanceof CheckRule) {
+ // rule rdf:type kruleCheck
+ add(triples, ruleNode, rdfType, (rule instanceof CheckRule) ? kruleCheck : kruleRule);
+ } else {
+ // rule rdf:type kruleRule
+ add(triples, ruleNode, rdfType, kruleRule);
+ emitTriggers(triples, ruleNode, rule.getTriggers());
+ }
- emitTriggers(triples, ruleNode, rule.getTriggers());
-
// query rdf:type krule:Query
// rule krule:hasQuery query
long query = newBlankNode();
add(triples, query, rdfType, kruleQuery);
add(triples, ruleNode, kruleHasQuery, query);
- emitSelection(triples, query, rule.getHead());
+ if (rule instanceof CheckRule) emitSelection(triples, query, rule.getVariables());
+ else emitSelection(triples, query, rule.getHead());
+
emitWhereClause(triples, query, rule.getBody(), rule.getBodySubtractions());
return triples;
@@ -218,18 +241,47 @@
* @throws URISyntaxException If a selected URI is incorrectly formed.
*/
private void emitSelection(List<long[]> triples, long query, Predicate selection) throws URIParseException, LocalizeException, URISyntaxException {
+ emitSelection(triples, query, Collections.singletonList(selection));
+ }
+
+
+ /**
+ * Adds the head of a rule to the triples.
+ * @param triples The list of triples to append to.
+ * @param selection The list of predicates that makes up the head of a rule.
+ * @throws LocalizeException Unable to create a new blank node.
+ * @throws URISyntaxException If a selected URI is incorrectly formed.
+ */
+ private void emitSelection(List<long[]> triples, long query, List<Predicate> selection) throws URIParseException, LocalizeException, URISyntaxException {
+ List<RDFNode> sel = new ArrayList<RDFNode>();
+ for (Predicate p: selection) {
+ sel.add(p.getSubject());
+ sel.add(p.getPredicate());
+ sel.add(p.getObject());
+ }
+ emitSelection(triples, query, sel);
+ }
+
+
+ /**
+ * Adds the selection elements of a rule to the triples.
+ * @param triples The list of triples to append to.
+ * @param selection The selection that makes up the variables or the head of a rule.
+ * @throws LocalizeException Unable to create a new blank node.
+ * @throws URISyntaxException If a selected URI is incorrectly formed.
+ */
+ private void emitSelection(List<long[]> triples, long query, Collection<? extends RDFNode> selection) throws URIParseException, LocalizeException, URISyntaxException {
// seq rdf:type rdf:Seq
// query krule:selectionVariables seq
long seq = newBlankNode();
add(triples, seq, rdfType, rdfSeq);
add(triples, query, kruleSelVars, seq);
- // seq rdf:_1 getSubject()
- // seq rdf:_2 getPredicate()
- // seq rdf:_3 getObject()
- add(triples, seq, getSeq(1), toKruleNode(selection.getSubject().getRdfLabel()));
- add(triples, seq, getSeq(2), toKruleNode(selection.getPredicate().getRdfLabel()));
- add(triples, seq, getSeq(3), toKruleNode(selection.getObject().getRdfLabel()));
+ // seq rdf:_n selection(n) ...
+ int n = 1;
+ for (RDFNode s: selection) {
+ add(triples, seq, getSeq(n++), toKruleNode(s.getRdfLabel()));
+ }
}
@@ -262,21 +314,21 @@
* @throws URISyntaxException If one of the URIs in the constraint has an invalid syntax.
*/
private void emitSubtractions(List<long[]> triples, long diff, List<Predicate> body, List<Predicate> subs) throws URIParseException, LocalizeException, URISyntaxException {
- // constraintExpr rdf:type krule:Difference
+ // diff rdf:type krule:Difference
add(triples, diff, rdfType, kruleDifference);
long argument = newBlankNode();
- // diff krule:argument argument
- add(triples, diff, kruleArgument, argument);
+ // diff krule:minuend argument
+ add(triples, diff, kruleMinuend, argument);
int lastElt = subs.size() - 1;
if (lastElt == 0) emitConjunction(triples, argument, body);
else emitSubtractions(triples, argument, body, subs.subList(0, lastElt));
// last argument in subtraction
- // diff krule:argument argument
+ // diff krule:subtrahend argument
argument = newBlankNode();
- add(triples, diff, kruleArgument, argument);
+ add(triples, diff, kruleSubtrahend, argument);
emitSimpleConstraint(triples, argument, subs.get(lastElt));
}
Modified: branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/RuleWriter.java
===================================================================
--- branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/RuleWriter.java 2009-03-17 19:54:23 UTC (rev 1620)
+++ branches/consistency/src/jar/content-rlog/java/org/mulgara/krule/rlog/ast/output/RuleWriter.java 2009-03-18 22:24:10 UTC (rev 1621)
@@ -16,12 +16,16 @@
package org.mulgara.krule.rlog.ast.output;
+import org.mulgara.krule.rlog.ast.CheckRule;
import org.mulgara.krule.rlog.ast.Predicate;
import org.mulgara.krule.rlog.ast.Rule;
import org.mulgara.krule.rlog.parser.URIParseException;
+import org.mulgara.krule.rlog.rdf.RDFNode;
import java.io.PrintStream;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
@@ -58,11 +62,18 @@
* @param r The rule to print.
*/
private void emitRule(PrintStream out, Rule r) throws URIParseException {
- out.println(" <krule:Rule rdf:about=\"#" + r.getName() + "\">");
- emitTriggers(out, r.getTriggers());
+ if (r instanceof CheckRule) {
+ out.println(" <krule:ConsistencyCheck rdf:about=\"#" + r.getName() + "\">");
+ } else {
+ out.println(" <krule:Rule rdf:about=\"#" + r.getName() + "\">");
+ emitTriggers(out, r.getTriggers());
+ }
out.println(" <hasQuery>\n" +
" <Query>");
- emitSelection(out, r.getHead());
+
+ if (r instanceof CheckRule) emitSelection(out, r.getVariables());
+ else emitSelection(out, r.getHead());
+
emitWhereClause(out, r.getBody(), r.getBodySubtractions());
out.println(" </Query>\n" +
" </hasQuery>\n" +
@@ -86,15 +97,42 @@
* @param selection The selection that makes up the head of a rule.
*/
private void emitSelection(PrintStream out, Predicate selection) throws URIParseException {
+ emitSelection(out, Collections.singletonList(selection));
+ }
+
+
+ /**
+ * Prints the head for a rule to a PrintStream.
+ * @param out The PrintStream to send the selection to.
+ * @param selection The list of predicates that makes up the head of a rule.
+ */
+ private void emitSelection(PrintStream out, List<Predicate> selection) throws URIParseException {
+ List<RDFNode> sel = new ArrayList<RDFNode>();
+ for (Predicate p: selection) {
+ sel.add(p.getSubject());
+ sel.add(p.getPredicate());
+ sel.add(p.getObject());
+ }
+ emitSelection(out, sel);
+ }
+
+
+ /**
+ * Prints the selection values to a PrintStream.
+ * @param out The PrintStream to send the selection to.
+ * @param sel The elements to be selected.
+ */
+ private void emitSelection(PrintStream out, Collection<? extends RDFNode> sel) throws URIParseException {
out.println(" <selectionVariables>\n" +
- " <rdf:Seq>\n" +
- " <rdf:li rdf:resource=\"" + selection.getSubject().getRdfLabel() + "\"/>\n" +
- " <rdf:li rdf:resource=\"" + selection.getPredicate().getRdfLabel() + "\"/>\n" +
- " <rdf:li rdf:resource=\"" + selection.getObject().getRdfLabel() + "\"/>\n" +
- " </rdf:Seq>\n" +
+ " <rdf:Seq>");
+ for (RDFNode s: sel) {
+ out.println(" <rdf:li rdf:resource=\"" + s.getRdfLabel() + "\"/>");
+ }
+ out.println(" </rdf:Seq>\n" +
" </selectionVariables>");
}
+
/**
* Prints the body for a rule to a PrintStream.
* @param out The PrintStream to send the where clause to.
@@ -112,13 +150,13 @@
private void emitSubtractions(PrintStream out, List<Predicate> body, List<Predicate> subs, int indent) throws URIParseException {
int lastElt = subs.size() - 1;
out.println(sp(indent) + "<Difference>\n" +
- sp(indent + 1) + "<argument>");
+ sp(indent + 1) + "<minuend>");
if (lastElt == 0) emitConjunction(out, body, indent + 2);
else emitSubtractions(out, body, subs.subList(0, lastElt), indent + 2);
- out.println(sp(indent + 1) + "</argument>\n" +
- sp(indent + 1) + "<argument>");
+ out.println(sp(indent + 1) + "</minuend>\n" +
+ sp(indent + 1) + "<subtrahend>");
emitSimpleConstraint(out, subs.get(lastElt), indent + 2);
- out.println(sp(indent + 1) + "</argument>\n" +
+ out.println(sp(indent + 1) + "</subtrahend>\n" +
sp(indent) + "</Difference>");
}
Added: branches/consistency/src/jar/krule/java/org/mulgara/krule/ConsistencyCheck.java
===================================================================
--- branches/consistency/src/jar/krule/java/org/mulgara/krule/ConsistencyCheck.java (rev 0)
+++ branches/consistency/src/jar/krule/java/org/mulgara/krule/ConsistencyCheck.java 2009-03-18 22:24:10 UTC (rev 1621)
@@ -0,0 +1,139 @@
+/*
+ * 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.krule;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.mulgara.query.Answer;
+import org.mulgara.query.QueryException;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.Variable;
+import org.mulgara.resolver.OperationContext;
+import org.mulgara.resolver.spi.Resolver;
+import org.mulgara.resolver.spi.ResolverException;
+import org.mulgara.resolver.spi.SystemResolver;
+
+/**
+ * A rule that generates no data, but instead checks that the data is consistent.
+ *
+ * @created Mar 18, 2009
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class ConsistencyCheck extends Rule {
+
+ /** Serialization ID */
+ private static final long serialVersionUID = 5514372363770138432L;
+
+ /** Logger. */
+ private static Logger logger = Logger.getLogger(ConsistencyCheck.class.getName());
+
+
+ /**
+ * Creates the consistency test as a rule.
+ * @param name The name of this rule.
+ */
+ public ConsistencyCheck(String name) {
+ super(name);
+ }
+
+
+ /**
+ * Adds a target for triggering. These are not legal for consistency checks.
+ * @param target The rule to be triggered when this rule is executed.
+ */
+ public void addTriggerTarget(Rule target) {
+ throw new IllegalStateException("Consistency checks cannot trigger other rules.");
+ }
+
+
+ /**
+ * Retrieves the list of subordinate rules.
+ * @return an immutable set of the subordinate rules.
+ */
+ public Set<Rule> getTriggerTargets() {
+ return Collections.emptySet();
+ }
+
+
+ /**
+ * Sets the query for this rule.
+ * @param queryStruct The query which retrieves data for this rule.
+ */
+ public void setQueryStruct(QueryStruct queryStruct) throws KruleStructureException {
+ this.query = queryStruct.extractQuery();
+ }
+
+
+ /**
+ * Runs this test.
+ * TODO: count the size of each individual constraint
+ *
+ * @param context The context to query against.
+ * @param resolver The resolver to add data with.
+ * @param sysResolver The resolver to localize data with.
+ */
+ public void execute(OperationContext context, Resolver resolver, SystemResolver sysResolver) throws QueryException, TuplesException, ResolverException {
+ // Tests the output of this rule
+ Answer answer = null;
+ logger.debug("Running consistency check: " + name);
+ try {
+ answer = context.doQuery(query);
+ } catch (Exception e) {
+ throw new QueryException("Unable to access data in rule.", e);
+ }
+ try {
+ // compare the size of the result data
+ long c = answer.getRowCount();
+ if (0 != c) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Failed consistency check: " + name);
+ logOutput(answer);
+ }
+ throw new QueryException("Consistency check failed for rule \"" + name + "\". Got " + c + " failure results.");
+ }
+ } finally {
+ answer.close();
+ }
+ }
+
+
+ /**
+ * Send the result of a query to the logger.
+ * @param ans The result of the query to log.
+ */
+ private void logOutput(Answer ans) {
+ try {
+ ans.beforeFirst();
+ Variable[] vars = ans.getVariables();
+ StringBuilder line = new StringBuilder();
+ for (Variable v: vars) line.append(v).append(" ");
+ logger.debug(line.toString());
+ line = new StringBuilder();
+ while (ans.next()) {
+ for (int c = 0; c < vars.length; c++) {
+ if (c != 0) line.append(", ");
+ line.append(ans.getObject(c));
+ }
+ line.append("\n");
+ }
+ logger.debug(line);
+ } catch (TuplesException e) {
+ logger.error("Error reading failure in consistency check.", e);
+ }
+ }
+
+}
Modified: branches/consistency/src/jar/krule/java/org/mulgara/krule/KruleLoader.java
===================================================================
--- branches/consistency/src/jar/krule/java/org/mulgara/krule/KruleLoader.java 2009-03-17 19:54:23 UTC (rev 1620)
+++ branches/consistency/src/jar/krule/java/org/mulgara/krule/KruleLoader.java 2009-03-18 22:24:10 UTC (rev 1621)
@@ -34,6 +34,8 @@
import org.mulgara.query.rdf.URIReferenceImpl;
import org.mulgara.resolver.OperationContext;
import org.mulgara.rules.*;
+import org.mulgara.util.functional.Pair;
+
import static org.mulgara.query.rdf.Mulgara.PREFIX_GRAPH;
/**
@@ -124,6 +126,12 @@
/** URI for the argument property. */
private static final String ARGUMENT_STR = KRULE + "argument";
+ /** URI for the minuend property. */
+ private static final String MINUEND_STR = KRULE + "minuend";
+
+ /** URI for the subtrahend property. */
+ private static final String SUBTRAHEND_STR = KRULE + "subtrahend";
+
/** URI for the transitive constraint argument. */
private static final String TRANSITIVE_ARGUMENT_STR = KRULE + "transitiveArgument";
@@ -163,6 +171,9 @@
/** URI for rule type. */
private static final String RULE_STR = KRULE + "Rule";
+ /** URI for consistency check type. */
+ private static final String CHECK_STR = KRULE + "ConsistencyCheck";
+
/** URI for query type. */
private static final String QUERY_STR = KRULE + "Query";
@@ -205,6 +216,12 @@
/** RDF reference for the argument property. */
public static final URIReferenceImpl ARGUMENT = new URIReferenceImpl(URI.create(ARGUMENT_STR));
+ /** RDF reference for the minuend property. */
+ public static final URIReferenceImpl MINUEND = new URIReferenceImpl(URI.create(MINUEND_STR));
+
+ /** RDF reference for the subtrahend property. */
+ public static final URIReferenceImpl SUBTRAHEND = new URIReferenceImpl(URI.create(SUBTRAHEND_STR));
+
/** RDF reference for the transitive constraint argument. */
public static final URIReferenceImpl TRANSITIVE_ARGUMENT = new URIReferenceImpl(URI.create(TRANSITIVE_ARGUMENT_STR));
@@ -244,6 +261,9 @@
/** RDF reference for the Rule type. */
public static final URIReferenceImpl RULE = new URIReferenceImpl(URI.create(RULE_STR));
+ /** RDF reference for the Consistency Check type. */
+ public static final URIReferenceImpl CHECK = new URIReferenceImpl(URI.create(CHECK_STR));
+
/** RDF reference for the Query type. */
public static final URIReferenceImpl QUERY = new URIReferenceImpl(URI.create(QUERY_STR));
@@ -380,7 +400,15 @@
private RuleStructure findRules() throws QueryException, TuplesException {
// select $rule from <ruleGraph> where $rule <rdf:type> <krule:Rule>
Variable ruleV = new Variable("rule");
- Query query = createQuery(new ConstraintImpl(ruleV, RDF_TYPE, RULE), ruleV);
+ Variable ruletypeV = new Variable("ruletype");
+ ConstraintExpression where = new ConstraintConjunction(
+ new ConstraintImpl(ruleV, RDF_TYPE, ruletypeV),
+ new ConstraintDisjunction(
+ new ConstraintIs(ruletypeV, RULE),
+ new ConstraintIs(ruletypeV, CHECK)
+ )
+ );
+ Query query = createQuery(where, ruleV, ruletypeV);
Answer ruleAnswer = query(query);
if (logger.isDebugEnabled()) logger.debug("Got response for rule query");
@@ -392,7 +420,11 @@
// create all the rules
while (ruleAnswer.next()) {
// create the rule and add it to the set
- rules.add(new Rule(ruleAnswer.getObject(0).toString()));
+ URIReference type = (URIReference)ruleAnswer.getObject(1);
+ String name = ruleAnswer.getObject(0).toString();
+ if (type.equals(RULE)) rules.add(new Rule(name));
+ else if (type.equals(CHECK)) rules.add(new ConsistencyCheck(name));
+ else throw new QueryException("Unexpected type for rule: " + name + "(" + type + ")");
}
} finally {
ruleAnswer.close();
@@ -477,34 +509,31 @@
// get the length of the sequence prefix
int prefixLength = ((URI)aliases.get("rdf")).toString().length() + 1;
// get the variables and values as elements with the appropriate type
- URIReference[] elements = new URIReference[3];
- URIReference[] types = new URIReference[3];
+ List<URIReference> elements = new ArrayList<URIReference>();
+ List<URIReference> types = new ArrayList<URIReference>();
try {
while (answer.next()) {
if (logger.isDebugEnabled()) logger.debug("Getting element from " + answer.getObject(0));
// work out the position of the element. Subject=0 Predicate=1 Object=2
int seqNr = Integer.parseInt(answer.getObject(0).toString().substring(prefixLength)) - 1;
if (logger.isDebugEnabled()) logger.debug("parsed: " + seqNr);
- if (seqNr > elements.length) {
- throw new KruleStructureException("Rule " + rule.getName() + " has too many insertion elements. Found sequence number: " + seqNr);
- }
// get the selection element and its type
- elements[seqNr] = (URIReference)answer.getObject(1);
- types[seqNr] = (URIReference)answer.getObject(2);
- if (logger.isDebugEnabled()) logger.debug("Nr: " + seqNr + ", v: " + elements[seqNr] + ", type: " + types[seqNr]);
+ setList(elements, seqNr, (URIReference)answer.getObject(1));
+ setList(types, seqNr, (URIReference)answer.getObject(2));
+ if (logger.isDebugEnabled()) logger.debug("Nr: " + seqNr + ", v: " + elements.get(seqNr) + ", type: " + types.get(seqNr));
}
} finally {
answer.close();
}
- for (int select = 0; select < elements.length; select++) {
- if (elements[select] == null || types[select] == null) {
+ for (int select = 0; select < elements.size(); select++) {
+ if (elements.get(select) == null || types.get(select) == null) {
// one element was set. Get a descriptive error message
StringBuffer errorMsg = new StringBuffer();
- for (int s = 0; s < elements.length; s++) {
- if (elements[s] == null) errorMsg.append(" <null>");
- else errorMsg.append(" ").append(elements[s]);
- if (types[s] == null) errorMsg.append("^^<null>");
- else errorMsg.append("^^<").append(types[s]).append(">");
+ for (int s = 0; s < elements.size(); s++) {
+ if (elements.get(s) == null) errorMsg.append(" <null>");
+ else errorMsg.append(" ").append(elements.get(s));
+ if (types.get(s) == null) errorMsg.append("^^<null>");
+ else errorMsg.append("^^<").append(types.get(s)).append(">");
}
throw new KruleStructureException("Rule " + rule.getName() + " does not have enough insertion elements. Got: " + errorMsg);
}
@@ -709,7 +738,7 @@
URIReference ref = (URIReference)answer.getObject(0);
Literal name = (Literal)answer.getObject(1);
if (logger.isDebugEnabled()) logger.debug("Mapping <" + ref + "> to <" + name + ">");
- varReferences.put(ref, new Variable(name.toString()));
+ varReferences.put(ref, new Variable(name.getLexicalForm()));
}
} finally {
answer.close();
@@ -844,30 +873,42 @@
// build constraints in place, recursively constructing child constraints until all are found
if (logger.isDebugEnabled()) logger.debug("Querying for Join constraints.");
- // select $constraint $constraint2 $type from <ruleGraph>
- // where $constraint <krule:argument> $constraint2
+ // don't look for the type of the child constraints. krule:argument has range of Constraint.
+
+ // select $constraint $arg $constraint2 $type from <ruleGraph>
+ // where $constraint $arg $constraint2
// and $constraint <rdf:type> $type
// and ($type <mulgara:is> <krule:ConstraintConjunction>
// or $type <mulgara:is> <krule:ConstraintDisjunction>)
+ // and ($arg <mulgara:is> <krule:argument>
+ // or $arg <mulgara:is> <krule:minuend>
+ // or $arg <mulgara:is> <krule:subtrahend>)
Variable constraintV = new Variable("constraint");
+ Variable argV = new Variable("arg");
Variable constraint2V = new Variable("constraint2");
Variable typeV = new Variable("type");
ConstraintExpression where = new ConstraintConjunction(
- new ConstraintImpl(constraintV, ARGUMENT, constraint2V),
+ new ConstraintImpl(constraintV, argV, constraint2V),
new ConstraintImpl(constraintV, RDF_TYPE, typeV),
new ConstraintDisjunction(
new ConstraintIs(typeV, CONSTRAINT_CONJUNCTION),
- new ConstraintIs(typeV, CONSTRAINT_DISJUNCTION)
+ new ConstraintIs(typeV, CONSTRAINT_DISJUNCTION),
+ new ConstraintIs(typeV, DIFFERENCE)
+ ),
+ new ConstraintDisjunction(
+ new ConstraintIs(argV, ARGUMENT),
+ new ConstraintIs(argV, MINUEND),
+ new ConstraintIs(argV, SUBTRAHEND)
)
);
- Query query = createQuery(where, constraintV, constraint2V, typeV);
+ Query query = createQuery(where, constraintV, argV, constraint2V, typeV);
Answer answer = query(query);
if (logger.isDebugEnabled()) logger.debug("Found all join constraints.");
// accumulate all the constraint links and types
// create a map of join constraints to the constraints that they join
- Map<Node,Set<Node>> constraintLinks = new HashMap<Node,Set<Node>>();
+ Map<Node,Set<Pair<Node,Node>>> constraintLinks = new HashMap<Node,Set<Pair<Node,Node>>>();
// map the join constraints to the type of join
Map<Node,URIReference> joinTypes = new HashMap<Node,URIReference>();
@@ -876,13 +917,16 @@
// map each reference to the associated argument and type
while (answer.next()) {
Node constraintNode = (Node)answer.getObject(0);
- Node constraintNode2 = (Node)answer.getObject(1);
- URIReference type = (URIReference)answer.getObject(2);
- if (logger.isDebugEnabled()) logger.debug("constraint (" + type + ")<" + constraintNode + "> -> <" + constraintNode2 + ">");
- // map the constraint to its argument
- addLink(constraintLinks, constraintNode, constraintNode2);
+ URIReference arg = (URIReference)answer.getObject(1);
+ Node constraintNode2 = (Node)answer.getObject(2);
+ URIReference type = (URIReference)answer.getObject(3);
+ if (logger.isDebugEnabled()) logger.debug("constraint (" + type + ")<" + constraintNode + "> <" + arg + "><" + constraintNode2 + ">");
+ // map the constraint to its operand: constraintNode2
+ addLink(constraintLinks, constraintNode, new Pair<Node,Node>(arg, constraintNode2));
// map the type
- joinTypes.put(constraintNode, type);
+ URIReference storedType = joinTypes.get(constraintNode);
+ if (storedType == null) joinTypes.put(constraintNode, type);
+ else if (!storedType.equals(type)) throw new KruleStructureException("Varying types in constraint operations in the rule structure");
}
} finally {
answer.close();
@@ -890,19 +934,19 @@
if (logger.isDebugEnabled()) logger.debug("mapping join constraint RDF nodes to join constraint objects");
// collect all arguments together into constraints and map the node to the constraint
- for (Map.Entry<Node,Set<Node>> entry: constraintLinks.entrySet()) {
+ for (Map.Entry<Node,Set<Pair<Node,Node>>> entry: constraintLinks.entrySet()) {
// get the constraint node in question
Node constraintNode = entry.getKey();
// see if it maps to a constraint
if (constraintMap.get(constraintNode) == null) {
// the constraint does not exist
// get the argument nodes
- Set<Node> args = entry.getValue();
+ Set<Pair<Node,Node>> operands = entry.getValue();
// get the constraint's type
Node type = joinTypes.get(constraintNode);
- if (type == null) throw new KruleStructureException("No type (AND/OR) available on join constraint: " + constraintNode);
+ if (type == null) throw new KruleStructureException("No type (AND/OR/Minus) available on join constraint: " + constraintNode);
// convert the RDF nodes to constraints
- List<ConstraintExpression> constraintArgs = getConstraints(args, constraintLinks, joinTypes);
+ List<ConstraintExpression> constraintArgs = getConstraints(operands, constraintLinks, joinTypes);
ConstraintExpression joinConstraint = newJoinConstraint(type, constraintArgs);
if (logger.isDebugEnabled()) logger.debug("mapped " + constraintNode + " -> " + joinConstraint);
// build the join constraint, and map the node to it
@@ -1027,13 +1071,13 @@
* to be created. The constraintLinks and typeMap arguments are for constructing new
* constraint objects.
*
- * @param constraints The set of constraint nodes to get the constraints for. Whenever possible,
- * the constraints come from constraintMap.
- * @param constraintLinks Linkage of join constraints to their arguments. Used to create a new constraint.
+ * @param constraints The set of constraint nodes and their usage to get the constraints for.
+ * Whenever possible, the constraints come from constraintMap.
+ * @param constraintLinks Linkage of join constraints to their arguments (and argument usage). Used to create a new constraint.
* @param typeMap Maps constraint nodes to their type. Used to create a new constraint.
* @throws KruleStructureException There was an error in the RDF data structure.
*/
- private List<ConstraintExpression> getConstraints(Set<Node> constraints, Map<Node,Set<Node>> constraintLinks, Map<Node,URIReference> typeMap) throws KruleStructureException {
+ private List<ConstraintExpression> getConstraints(Set<Pair<Node,Node>> constraints, Map<Node,Set<Pair<Node,Node>>> constraintLinks, Map<Node,URIReference> typeMap) throws KruleStructureException {
if (logger.isDebugEnabled()) logger.debug("converting nodes to constraint list: " + constraints);
// build the return list
@@ -1044,21 +1088,27 @@
return cList;
}
// go through the arguments
- for (Node cNode: constraints) {
+ for (Pair<Node,Node> constraintUsage: constraints) {
+ Node usage = constraintUsage.first(); // one of: argument/minuend/subtrahend
+ Node cNode = constraintUsage.second();
if (logger.isDebugEnabled()) logger.debug("converting: " + cNode);
// get the constraint expression object
ConstraintExpression constraintExpr = (ConstraintExpression)constraintMap.get(cNode);
if (constraintExpr == null) {
if (logger.isDebugEnabled()) logger.debug(cNode.toString() + " not yet mapped to constraint");
// constraint expression object does not yet exist, get its arguments
- Set<Node> constraintArgNodes = constraintLinks.get(cNode);
+ Set<Pair<Node,Node>> constraintArgNodes = constraintLinks.get(cNode);
// build the constraint expression - get the arguments as a list of constraints
List<ConstraintExpression> constraintArgs = getConstraints(constraintArgNodes, constraintLinks, typeMap);
constraintExpr = newJoinConstraint((Node)typeMap.get(cNode), constraintArgs);
}
// add the constraint argument to the list
- if (constraintExpr != null) cList.add(constraintExpr);
- else logger.warn("Missing constraint expression. Ignoring.");
+ if (constraintExpr != null) {
+ if (usage.equals(MINUEND)) setList(cList, 0, constraintExpr);
+ else if (usage.equals(SUBTRAHEND)) setList(cList, 1, constraintExpr);
+ else if (usage.equals(ARGUMENT)) cList.add(constraintExpr);
+ else throw new KruleStructureException("Unknown argument type for " + cNode + ": " + usage);
+ } else logger.warn("Missing constraint expression. Ignoring.");
}
return cList;
}
@@ -1080,8 +1130,11 @@
return new ConstraintConjunction(args);
} else if (type.equals(CONSTRAINT_DISJUNCTION)) {
return new ConstraintDisjunction(args);
+ } else if (type.equals(DIFFERENCE)) {
+ if (args.size() != 2) throw new KruleStructureException("Difference constraints require 2 arguments: args=" + args);
+ return new ConstraintDifference(args.get(0), args.get(1));
}
- throw new KruleStructureException("Unknown join constraint type (not AND/OR): " + type);
+ throw new KruleStructureException("Unknown join constraint type (not AND/OR/Minus): " + type);
}
@@ -1137,30 +1190,42 @@
/**
- * Maps a node to another node, creating the entry if it does not exist yet.
+ * Maps a node to data about a nodee, creating the entry if it does not exist yet.
*
* @param map The mapping of nodes to tuples.
* @param node1 The node to map.
- * @param node2 The node to map it to.
+ * @param nodeData The node data to map it to.
*/
- private static void addLink(Map<Node,Set<Node>> map, Node node1, Node node2) {
+ private static void addLink(Map<Node,Set<Pair<Node,Node>>> map, Node node1, Pair<Node,Node> nodeData) {
// get the current set of properties
- Set<Node> links = map.get(node1);
+ Set<Pair<Node,Node>> links = map.get(node1);
// check that the set exists
if (links == null) {
// no, so create
- links = new HashSet<Node>();
- links.add(node2);
+ links = new HashSet<Pair<Node,Node>>();
+ links.add(nodeData);
// add to the map
map.put(node1, links);
} else {
// update the map to hold the new value
- links.add(node2);
+ links.add(nodeData);
}
}
/**
+ * Sets an element in a list, expanding the list if necessary.
+ * @param list The list to update.
+ * @param offset The offset to write to in the list.
+ * @param value The value to write to the list.
+ */
+ private static <T> void setList(List<T> list, int offset, T value) {
+ while (offset >= list.size()) list.add(null);
+ list.set(offset, value);
+ }
+
+
+ /**
* Utility method to create a query.
* @param constraintExpression The constraint expression making up the WHERE clause of the query.
* @param selection The variables to select in the query.
Modified: branches/consistency/src/jar/krule/java/org/mulgara/krule/QueryStruct.java
===================================================================
--- branches/consistency/src/jar/krule/java/org/mulgara/krule/QueryStruct.java 2009-03-17 19:54:23 UTC (rev 1620)
+++ branches/consistency/src/jar/krule/java/org/mulgara/krule/QueryStruct.java 2009-03-18 22:24:10 UTC (rev 1621)
@@ -62,7 +62,7 @@
private static Logger logger = Logger.getLogger(QueryStruct.class.getName());
/** The selection list. */
- private ConstraintElement[] select = new ConstraintElement[3];
+ private ConstraintElement[] select;
/** List of elements which are variables, or ConstantValues. */
private List<SelectElement> variables;
@@ -80,8 +80,8 @@
/**
* Constructor. Converts string descriptions of the values and variables into the constraint elements.
*
- * @param vs The element nodes.
- * @param types The types of the elements, defined in the krule namespace.
+ * @param valueSelection The element nodes.
+ * @param selTypes The types of the elements, defined in the krule namespace.
* @param alias The aliases used in the query process.
* @param uriReferences A map of all krule:ref_* objects to the appropriate {@link org.jrdf.graph.URIReference}s.
* @param varReferences A map of all krule:var_* objects to the appropriate name.
@@ -89,19 +89,27 @@
* or the references are not found in the references map.
*/
public QueryStruct(
- URIReference[] vs, URIReference[] types, Map<String,URI> alias,
+ List<URIReference> valueSelection, List<URIReference> selTypes, Map<String,URI> alias,
Map<URIReference,URIReference> uriReferences, Map<URIReference,Variable> varReferences,
Map<Node,Literal> litReferences
) {
- if (vs.length != 3 && types.length != 3) {
+ if (valueSelection.size() <= 0 || selTypes.size() <= 0 || valueSelection.size() != selTypes.size()) {
throw new IllegalArgumentException("Wrong number of elements for a rule query");
}
+ URIReference[] vs = valueSelection.toArray(new URIReference[valueSelection.size()]);
+ URIReference[] types = selTypes.toArray(new URIReference[selTypes.size()]);
+
+ // If there is a non-multiple of 3 in the selection variables, then this is a check rule
+ // and we can only select variables in check rules
+ boolean varsOnly = vs.length % 3 != 0;
+
VariableFactory variableFactory = new VariableFactoryImpl();
// set up a list of variables
variables = new ArrayList<SelectElement>();
+ select = new ConstraintElement[vs.length];
// convert the parameters to usable objects
for (int i = 0; i < 3; i++) {
@@ -109,6 +117,9 @@
// check the type
if (types[i].equals(KruleLoader.URI_REF)) {
+ // check that this didn't have a non-multiple of 3 in the selection values
+ if (varsOnly) throw new IllegalArgumentException("Wrong number of elements for a rule query: " + vs.length);
+
// get the referred value from the map
select[i] = (URIReferenceImpl)uriReferences.get(element);
// assume that literals do not have the "Value" type inferred
@@ -122,9 +133,13 @@
} else if (types[i].equals(KruleLoader.LITERAL)) {
- if (i != 2) {
+ if (i % 3 != 2) {
throw new IllegalArgumentException("Selection literal in illegal position in query");
}
+
+ // check that this didn't have a non-multiple of 3 in the selection values
+ if (varsOnly) throw new IllegalArgumentException("Wrong number of elements for a rule query: " + vs.length);
+
// get the literal
select[i] = (LiteralImpl)litReferences.get(element);
variables.add(new ConstantValue(variableFactory.newVariable(), (LiteralImpl)select[i]));
@@ -143,6 +158,15 @@
/**
+ * Returns the number of elements to be returned from this query.
+ * @return The number of selection elements from the query.
+ */
+ public int elementCount() {
+ return select.length;
+ }
+
+
+ /**
* Retrieve the element <em>n</em>.
*
* @param n The element number to retrieve.
@@ -150,7 +174,7 @@
* @throws IndexOutOfBoundsException If n is larger than 3.
*/
public ConstraintElement getElement(int n) {
- assert n < 3;
+ assert n < select.length;
return select[n];
}
Modified: branches/consistency/src/jar/krule/java/org/mulgara/krule/Rule.java
===================================================================
--- branches/consistency/src/jar/krule/java/org/mulgara/krule/Rule.java 2009-03-17 19:54:23 UTC (rev 1620)
+++ branches/consistency/src/jar/krule/java/org/mulgara/krule/Rule.java 2009-03-18 22:24:10 UTC (rev 1621)
@@ -51,13 +51,13 @@
private static Logger logger = Logger.getLogger(Rule.class.getName());
/** The name of this rule. */
- private String name;
+ protected String name;
/** The rules to be triggered when this rule generates statements.*/
private Set<Rule> triggerSet;
/** The query for this rule. This contains the information for the base model. */
- private Query query;
+ protected Query query;
/** The graph receiving the inferred data. */
private long targetGraph = UNINITIALIZED;
@@ -66,7 +66,7 @@
private long lastCount;
/** The structure containing this rule */
- private RuleStructure ruleStruct;
+ protected RuleStructure ruleStruct;
// TODO: Change this to a map of constraints to longs
@@ -112,11 +112,15 @@
/**
- * Sets the query for this rule.
+ * Sets the query for this rule. Must be a valid query for inserting data, meaning that it
+ * returns a multiple of 3 elements.
*
* @param queryStruct The query which retrieves data for this rule.
+ * @throws KruleStructureException If the query does not return a multiple of 3 elements.
*/
- public void setQueryStruct(QueryStruct queryStruct) {
+ public void setQueryStruct(QueryStruct queryStruct) throws KruleStructureException {
+ int e = queryStruct.elementCount();
+ if (e == 0 || e % 3 != 0) throw new KruleStructureException("Rule \"" + name + "\" attempting to generate the wrong number of elements (must be a multiple of 3): " + e);
this.query = queryStruct.extractQuery();
}
More information about the Mulgara-svn
mailing list