001: /******************************************************************
002: * File: Functor.java
003: * Created by: Dave Reynolds
004: * Created on: 29-Mar-03
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: Functor.java,v 1.24 2008/01/02 12:07:47 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner.rulesys;
010:
011: import com.hp.hpl.jena.graph.*;
012: import com.hp.hpl.jena.util.PrintUtil;
013: import com.hp.hpl.jena.util.iterator.Filter;
014: import com.hp.hpl.jena.datatypes.*;
015: import org.apache.commons.logging.Log;
016: import org.apache.commons.logging.LogFactory;
017:
018: import java.util.*;
019:
020: /**
021: * A functor comprises a functor name and a list of
022: * arguments. The arguments are Nodes of any type except functor nodes
023: * (there is no functor nesting). Functors play three roles in rules -
024: * in heads they represent actions (procedural attachement); in bodies they
025: * represent builtin predicates; in TriplePatterns they represent embedded
026: * structured literals that are used to cache matched subgraphs such as
027: * restriction specifications.
028: *
029: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
030: * @version $Revision: 1.24 $ on $Date: 2008/01/02 12:07:47 $
031: */
032: public class Functor implements ClauseEntry {
033: /** Functor's name */
034: protected String name;
035:
036: /** Argument list - an array of nodes */
037: protected Node[] args;
038:
039: /** A built in that implements the functor */
040: protected Builtin implementor;
041:
042: /** A static Filter instance that detects triples with Functor objects */
043: public static final Filter acceptFilter = new Filter() {
044: public boolean accept(Object t) {
045: if (((Triple) t).getSubject().isLiteral())
046: return true;
047: Node n = ((Triple) t).getObject();
048: return n.isLiteral()
049: && n.getLiteralDatatype() == FunctorDatatype.theFunctorDatatype;
050: }
051: };
052:
053: protected static Log logger = LogFactory.getLog(Functor.class);
054:
055: /**
056: * Constructor.
057: * @param name the name of the functor
058: * @param args a list of nodes defining the arguments
059: */
060: public Functor(String name, List args) {
061: this .name = name;
062: this .args = (Node[]) args.toArray(new Node[] {});
063: }
064:
065: /**
066: * Constructor.
067: * @param name the name of the functor
068: * @param args an array of nodes defining the arguments, this will not be copied so beware of
069: * accidental structure sharing
070: */
071: public Functor(String name, Node[] args) {
072: this .name = name;
073: this .args = args;
074: }
075:
076: /**
077: * Constructor
078: * @param name the name of the functor
079: * @param args a list of nodes defining the arguments
080: * @param registry a table of builtins to consult to check for
081: * implementations of this functor when used as a rule clause
082: */
083: public Functor(String name, List args, BuiltinRegistry registry) {
084: this .name = name;
085: this .args = (Node[]) args.toArray(new Node[] {});
086: this .implementor = registry.getImplementation(name);
087: }
088:
089: /**
090: * Return the functor name
091: */
092: public String getName() {
093: return name;
094: }
095:
096: /**
097: * Return the functor aguments as an array of nodes
098: */
099: public Node[] getArgs() {
100: return args;
101: }
102:
103: /**
104: * Return the length of the functor argument array.
105: */
106: public int getArgLength() {
107: return args.length;
108: }
109:
110: /**
111: * Returns true if the functor is fully ground, no variables
112: */
113: public boolean isGround() {
114: for (int i = 0; i < args.length; i++) {
115: Node n = args[i];
116: if (n instanceof Node_RuleVariable || n instanceof Node_ANY) {
117: return false;
118: }
119: }
120: return true;
121: }
122:
123: /**
124: * Returns true if the functor is fully ground in the given environment
125: */
126: public boolean isGround(BindingEnvironment env) {
127: for (int i = 0; i < args.length; i++) {
128: Node n = args[i];
129: if (env.getGroundVersion(args[i]).isVariable())
130: return false;
131: }
132: return true;
133: }
134:
135: /**
136: * Execute the given built in as a body clause.
137: * @param context an execution context giving access to other relevant data
138: * @return true if the functor has an implementation and that implementation returns true when evaluated
139: */
140: public boolean evalAsBodyClause(RuleContext context) {
141: if (getImplementor() == null) {
142: logger.warn("Invoking undefined functor " + getName()
143: + " in " + context.getRule().toShortString());
144: return false;
145: }
146: return implementor.bodyCall(getBoundArgs(context.getEnv()),
147: args.length, context);
148: }
149:
150: /**
151: * Execute the given built in as a body clause, only if it is side-effect-free.
152: * @param context an execution context giving access to other relevant data
153: * @return true if the functor has an implementation and that implementation returns true when evaluated
154: */
155: public boolean safeEvalAsBodyClause(RuleContext context) {
156: if (getImplementor() == null) {
157: logger.warn("Invoking undefined functor " + getName()
158: + " in " + context.getRule().toShortString());
159: return false;
160: }
161: if (implementor.isSafe()) {
162: return implementor.bodyCall(getBoundArgs(context.getEnv()),
163: args.length, context);
164: } else {
165: return false;
166: }
167: }
168:
169: /**
170: * Return a new Node array containing the bound versions of this Functor's arguments
171: */
172: public Node[] getBoundArgs(BindingEnvironment env) {
173: Node[] boundargs = new Node[args.length];
174: for (int i = 0; i < args.length; i++) {
175: boundargs[i] = env.getGroundVersion(args[i]);
176: }
177: return boundargs;
178: }
179:
180: /**
181: * Return the Builtin that implements this functor
182: * @return the Builtin or null if there isn't one
183: */
184: public Builtin getImplementor() {
185: if (implementor == null) {
186: implementor = BuiltinRegistry.theRegistry
187: .getImplementation(name);
188: }
189: return implementor;
190: }
191:
192: /**
193: * Set the Builtin that implements this functor.
194: */
195: public void setImplementor(Builtin implementor) {
196: this .implementor = implementor;
197: }
198:
199: /**
200: * Printable string describing the functor
201: */
202: public String toString() {
203: StringBuffer buff = new StringBuffer(name);
204: buff.append("(");
205: for (int i = 0; i < args.length; i++) {
206: buff.append(PrintUtil.print(args[i]));
207: if (i < args.length - 1) {
208: buff.append(" ");
209: }
210: }
211: buff.append(")");
212: return buff.toString();
213: }
214:
215: /**
216: * tests that a given Node represents a functor
217: */
218: public static boolean isFunctor(Node n) {
219: if (n == null)
220: return false;
221: return n.isLiteral()
222: && n.getLiteralDatatype() == FunctorDatatype.theFunctorDatatype;
223: }
224:
225: /**
226: * Equality is based on structural comparison
227: */
228: public boolean equals(Object obj) {
229: if (obj instanceof Functor) {
230: Functor f2 = (Functor) obj;
231: if (name.equals(f2.name) && args.length == f2.args.length) {
232: for (int i = 0; i < args.length; i++) {
233: if (!args[i].sameValueAs(f2.args[i]))
234: return false;
235: }
236: return true;
237: }
238: }
239: return false;
240: }
241:
242: /** hash function override */
243: public int hashCode() {
244: return (name.hashCode()) ^ (args.length << 2);
245: }
246:
247: /**
248: * Compare Functors, taking into account variable indices.
249: * The equality function ignores differences between variables.
250: */
251: public boolean sameAs(Object o) {
252: if (o instanceof Functor) {
253: Functor f2 = (Functor) o;
254: if (name.equals(f2.name) && args.length == f2.args.length) {
255: for (int i = 0; i < args.length; i++) {
256: if (!Node_RuleVariable.sameNodeAs(args[i],
257: f2.args[i]))
258: return false;
259: }
260: return true;
261: }
262: }
263: return false;
264: }
265:
266: /**
267: * Create a functor and wrap it up as a Literal node
268: * @param name the name of the functor
269: * @param args an array of nodes defining the arguments, this will not be copied so beware of
270: * accidental structure sharing
271: */
272: public static Node makeFunctorNode(String name, Node[] args) {
273: return makeFunctorNode(new Functor(name, args));
274: }
275:
276: /**
277: * Wrap a functor as a Literal node
278: * @param f the functor data structure to be wrapped in a node.
279: */
280: public static Node makeFunctorNode(Functor f) {
281: return Node.createUncachedLiteral(f, null,
282: FunctorDatatype.theFunctorDatatype);
283: }
284:
285: /**
286: * Inner class. Dummy datatype definition for
287: * functor-valued literals.
288: */
289: public static class FunctorDatatype extends BaseDatatype {
290:
291: public FunctorDatatype() {
292: super ("urn:x-hp-jena:Functor");
293: }
294:
295: public static final RDFDatatype theFunctorDatatype = new FunctorDatatype();
296: }
297:
298: }
299:
300: /*
301: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
302: All rights reserved.
303:
304: Redistribution and use in source and binary forms, with or without
305: modification, are permitted provided that the following conditions
306: are met:
307:
308: 1. Redistributions of source code must retain the above copyright
309: notice, this list of conditions and the following disclaimer.
310:
311: 2. Redistributions in binary form must reproduce the above copyright
312: notice, this list of conditions and the following disclaimer in the
313: documentation and/or other materials provided with the distribution.
314:
315: 3. The name of the author may not be used to endorse or promote products
316: derived from this software without specific prior written permission.
317:
318: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
319: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
320: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
321: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
322: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
323: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
324: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
325: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
326: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
327: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
328: */
|