/* * The contents of this file are subject to the Mozilla Public License * Version 1.1 (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.mozilla.org/MPL/ * * 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. * * The Original Code is the Kowari Metadata Store. * * The Initial Developer of the Original Code is Plugged In Software Pty * Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002 * Plugged In Software Pty Ltd. All Rights Reserved. * * Contributor(s): N/A. * getModel() contributed by Netymon Pty Ltd on behalf of * The Australian Commonwealth Government under contract 4500507038. * * [NOTE: The text of this Exhibit A may differ slightly from the text * of the notices in the Source Code files of the Original Code. You * should use the text of this Exhibit A rather than the text found in the * Original Code Source Code for Your Modifications.] * */ package org.mulgara.resolver; // Java 2 standard packages; import java.util.HashSet; import java.util.Set; // Third party packages import org.apache.log4j.Logger; import org.jrdf.graph.Node; // Locally written packages import org.mulgara.query.*; import org.mulgara.resolver.spi.LocalizeException; import org.mulgara.resolver.spi.QueryEvaluationContext; import org.mulgara.resolver.spi.ResolverSession; import org.mulgara.store.tuples.LiteralTuples; import org.mulgara.store.tuples.Tuples; /** * This is an implementation of the trans function that begins or ends * (anchored) from a particular subject or object and only infers direct * relations to the given anchored constraint. * <p> * Example to infer only statements directly: <p></p> * <pre> * select <b> <rdfs:subClassOf> $zzz * where trans(<b> <rdfs:subClassOf> $zzz) ; * * select $xxx <rdfs:subClassOf> <b> * where trans($xxx <rdfs:subClassOf> <b>) ; * </pre></p> * * @created 2004-06-07 * * @author Andrew Newman * * @version $Revision: 1.8 $ * * @modified $Date: 2005/01/05 04:58:23 $ * * @maintenanceAuthor $Author: newmana $ * * @company <A href="mailto:info@PIsoftware.com">Plugged In Software</A> * * @copyright © 2003 <A href="http://www.PIsoftware.com/">Plugged In * Software Pty Ltd</A> * * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a> */ public abstract class DirectTransitiveFunction extends TransitiveFunction { /** Logger. */ private static final Logger logger = Logger.getLogger(DirectTransitiveFunction.class.getName()); /** * Resolves an unanchored transitive constraint. This means finding all statements matching * the predicate statement, and infering a new set of statements based on this. * * @param query the query for a set of statements to infer over. * @param constraint a constraint describing a transitive predicate with a * supported model type fourth element of the constraint is not a Variable * or is a Variable with the name _from. * @param graphExpression the GraphExpression to resolve the constraint against. * @param session the resolverSession against which to localize nodes. * @return the answer satisfying the <var>constraint</var> * @throws QueryException if the <var>constraint</var> has a model of an * unsupported type, or if the answer otherwise couldn't be determined * @throws TuplesException If there was a problem while moving around in results * from various query resolutions. */ public static Tuples infer(QueryEvaluationContext query, SingleTransitiveConstraint constraint, GraphExpression graphExpression, ResolverSession session) throws QueryException, TuplesException { if (logger.isDebugEnabled()) { logger.debug("Transitive Constraint is anchored"); } // Transitive constraint must have a fixed predicate if (!(constraint.getElement(1) instanceof Value)) { throw new QueryException("The predicate: " + constraint.getElement(1) + " must be a fixed value"); } // Either the subject is a variable and the object is a constant or // vice-versa. if (((constraint.getElement(0) instanceof Variable) && !(constraint.getElement(2) instanceof Value)) || ((constraint.getElement(0) instanceof Value) && !(constraint.getElement(2) instanceof Variable))) { throw new QueryException( "The subject: " + constraint.getElement(0) + " and the object: " + constraint.getElement(2) + " are invalid, one must be a variable " + "and the other a fixed value around a predicate."); } // Get the wrapped constraint. Constraint predConstraint = constraint.getTransConstraint(); // ask for all statements for this predicate Tuples initialTuples = query.resolve(graphExpression, predConstraint); // prepare to iterate through anchor initialTuples.beforeFirst(); boolean tuplesAvailable = initialTuples.next(); // if nothing matches, then there is no work to do if (!tuplesAvailable) { return initialTuples; } // The value and variable in the anchored constraint Long value; Variable variable; Variable tmpVariable; // construct a constraint without the fixed anchor Constraint openConstraint; // determine if this is a forward anchor or a back anchor try { if (predConstraint.getElement(0) instanceof Variable) { // back anchor [$x predicate anchor] value = new Long(session.lookup((Node)predConstraint.getElement(2))); variable = (Variable) predConstraint.getElement(0); // Create a temporary second variable by appending _ to the first variable name tmpVariable = new Variable(variable.getName() + "_"); // build the constraint with the temporary variable name openConstraint = new ConstraintImpl( variable, predConstraint.getElement(1), tmpVariable, predConstraint.getModel()); } else { // forward anchor [anchor predicate $x] value = new Long(session.lookup((Node)predConstraint.getElement(0))); variable = (Variable)predConstraint.getElement(2); // Create a temporary second variable by appending _ to the first variable name tmpVariable = new Variable(variable.getName() + "_"); // build the constraint with the temporary variable name openConstraint = new ConstraintImpl( tmpVariable, predConstraint.getElement(1), variable, predConstraint.getElement(3)); } } catch (LocalizeException el) { throw new QueryException("Unable to localize anchor", el); } if (logger.isDebugEnabled()) { logger.debug("Variable has name: " + variable.getName() + "; Value=" + value); } // find *all* statements with the given predicate Tuples predTuples = query.resolve(graphExpression, openConstraint); // set up the final result [$x] built from [$x predicate anchor] or [anchor predicate $x] LiteralTuples inferredResult = new LiteralTuples(new Variable[] {variable}); // set up given statement for inferences LiteralTuples given = new LiteralTuples(new Variable[] {tmpVariable}); // if there is a zero step, then start with the value if (constraint.isZeroStep()) inferredResult.appendTuple(new long[] {value}); // remember that the current value has been visited Set<Long> visited = new HashSet<Long>(); visited.add(value); long[] tupleRow = new long[1]; // iterate over each row of the tuples to set up a given clause for a new query // add the objects, and remember that we've been here // loop while we have data do { // add the current object to the given. Take advantage that initTuplesIndex // is always 0 for anchored constraints long var = initialTuples.getColumnValue(0); if (logger.isDebugEnabled()) { logger.debug("Found variable: " + var); } // add the object to the "given" tuples tupleRow[0] = var; given.appendTuple(tupleRow); } while ((tuplesAvailable = initialTuples.next())); // Get object/subject node value long subject = value.longValue(); // start inferring for the current subject, using this first set of objects // modifies the inferredResult value for us. inferTransitiveStatements(null, subject, predTuples, given, visited, inferredResult); if (logger.isDebugEnabled()) { logger.debug("Finished all inferencing"); } // clean up tuples initialTuples.close(); predTuples.close(); return inferredResult; } }