001: /*
002: (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: [See end of file]
004: $Id: Triple.java,v 1.27 2008/01/02 12:06:55 andy_seaborne Exp $
005: */
006:
007: package com.hp.hpl.jena.graph;
008:
009: import com.hp.hpl.jena.graph.test.NodeCreateUtils;
010: import com.hp.hpl.jena.shared.*;
011: import com.hp.hpl.jena.util.iterator.Filter;
012:
013: import java.util.*;
014:
015: /**
016: Triples are the basis for RDF statements; they have a subject, predicate, and
017: object field (all nodes) and express the notion that the relationship named
018: by the predicate holds between the subject and the object.
019:
020: @author Jeremy Carroll, kers
021: */
022: public class Triple implements TripleMatch {
023: private final Node subj, pred, obj;
024:
025: public Triple(Node s, Node p, Node o) {
026: if (s == null)
027: throw new UnsupportedOperationException(
028: "subject cannot be null");
029: if (p == null)
030: throw new UnsupportedOperationException(
031: "predicate cannot be null");
032: if (o == null)
033: throw new UnsupportedOperationException(
034: "object cannot be null");
035: subj = s;
036: pred = p;
037: obj = o;
038: }
039:
040: /**
041: return a human-readable string "subject @predicate object" describing the triple
042: */
043: public String toString() {
044: return toString(PrefixMapping.Standard);
045: }
046:
047: public String toString(PrefixMapping pm) {
048: return subj.toString(pm, true) + " @" + pred.toString(pm, true)
049: + " " + obj.toString(pm, true);
050: }
051:
052: /**
053: @return the subject of the triple
054: */
055: public final Node getSubject() {
056: return subj;
057: }
058:
059: /**
060: @return the predicate of the triple
061: */
062: public final Node getPredicate() {
063: return pred;
064: }
065:
066: /**
067: @return the object of the triple
068: */
069: public final Node getObject() {
070: return obj;
071: }
072:
073: public Node getMatchSubject() {
074: return anyToNull(subj);
075: }
076:
077: public Node getMatchPredicate() {
078: return anyToNull(pred);
079: }
080:
081: public Node getMatchObject() {
082: return anyToNull(obj);
083: }
084:
085: private static Node anyToNull(Node n) {
086: return Node.ANY.equals(n) ? null : n;
087: }
088:
089: private static Node nullToAny(Node n) {
090: return n == null ? Node.ANY : n;
091: }
092:
093: public Triple asTriple() {
094: return this ;
095: }
096:
097: public boolean isConcrete() {
098: return subj.isConcrete() && pred.isConcrete()
099: && obj.isConcrete();
100: }
101:
102: /**
103: Answer true if <code>o</code> is a Triple with the same subject, predicate,
104: and object as this triple.
105: */
106: public boolean equals(Object o) {
107: return o instanceof Triple
108: && ((Triple) o).sameAs(subj, pred, obj);
109: }
110:
111: /**
112: Answer true iff this triple has subject s, predicate p, and object o.
113: */
114: public boolean sameAs(Node s, Node p, Node o) {
115: return subj.equals(s) && pred.equals(p) && obj.equals(o);
116: }
117:
118: public boolean matches(Triple other) {
119: return other.matchedBy(subj, pred, obj);
120: }
121:
122: public boolean matches(Node s, Node p, Node o) {
123: return subj.matches(s) && pred.matches(p) && obj.matches(o);
124: }
125:
126: private boolean matchedBy(Node s, Node p, Node o) {
127: return s.matches(subj) && p.matches(pred) && o.matches(obj);
128: }
129:
130: public boolean subjectMatches(Node s) {
131: return subj.matches(s);
132: }
133:
134: public boolean predicateMatches(Node p) {
135: return pred.matches(p);
136: }
137:
138: public boolean objectMatches(Node o) {
139: return obj.matches(o);
140: }
141:
142: /**
143: The hash-code of a triple is the hash-codes of its components munged
144: together: see hashCode(S, P, O).
145: */
146: public int hashCode() {
147: return hashCode(subj, pred, obj);
148: }
149:
150: /**
151: Return the munged hashCodes of the specified nodes, an exclusive-or of
152: the slightly-shifted component hashcodes; this means (almost) all of the bits
153: count, and the order matters, so (S @P O) has a different hash from
154: (O @P S), etc.
155: */
156: public static int hashCode(Node s, Node p, Node o) {
157: return (s.hashCode() >> 1) ^ p.hashCode() ^ (o.hashCode() << 1);
158: }
159:
160: /**
161: Factory method for creating triples, allows caching opportunities. Attempts
162: to use triples from the cache, if any suitable ones exist.
163:
164: @return a triple with subject=s, predicate=p, object=o
165: */
166: public static Triple create(Node s, Node p, Node o) {
167: Triple already = cache.get(s, p, o);
168: return already == null ? cache.put(new Triple(s, p, o))
169: : already;
170: }
171:
172: /**
173: The cache of already-created triples.
174: */
175: protected static TripleCache cache = new TripleCache();
176:
177: public static Triple createMatch(Node s, Node p, Node o) {
178: return Triple.create(nullToAny(s), nullToAny(p), nullToAny(o));
179: }
180:
181: /**
182: Utility factory method for creating a triple based on the content of an
183: "S P O" string. The S, P, O are processed by Node.create, see which for
184: details of the supported syntax. This method exists to support test code.
185: Nodes are interpreted using the Standard prefix mapping.
186: */
187:
188: public static Triple create(String fact) {
189: return create(PrefixMapping.Standard, fact);
190: }
191:
192: /**
193: Utility factory as for create(String), but allowing the PrefixMapping to
194: be specified explicitly.
195: */
196: public static Triple create(PrefixMapping pm, String fact) {
197: StringTokenizer st = new StringTokenizer(fact);
198: Node sub = NodeCreateUtils.create(pm, st.nextToken());
199: Node pred = NodeCreateUtils.create(pm, st.nextToken());
200: Node obj = NodeCreateUtils.create(pm, st.nextToken());
201: return Triple.create(sub, pred, obj);
202: }
203:
204: /**
205: A Triple that is wildcarded in all fields.
206: */
207: public static final Triple ANY = Triple.create(Node.ANY, Node.ANY,
208: Node.ANY);
209:
210: /**
211: A Field is a selector from Triples; it allows selectors to be passed
212: around as if they were functions, hooray.
213: */
214: public static abstract class Field {
215: public abstract Node getField(Triple t);
216:
217: public abstract Filter filterOn(Node n);
218:
219: public final Filter filterOn(Triple t) {
220: return filterOn(getField(t));
221: }
222:
223: public static final Field getSubject = new Field() {
224: public Node getField(Triple t) {
225: return t.subj;
226: }
227:
228: public Filter filterOn(final Node n) {
229: return n.isConcrete() ? new Filter() {
230: public boolean accept(Object x) {
231: return n.equals(((Triple) x).subj);
232: }
233: } : Filter.any;
234: }
235: };
236:
237: public static final Field getObject = new Field() {
238: public Node getField(Triple t) {
239: return t.obj;
240: }
241:
242: public Filter filterOn(final Node n) {
243: return n.isConcrete() ? new Filter() {
244: public boolean accept(Object x) {
245: return n.sameValueAs(((Triple) x).obj);
246: }
247: } : Filter.any;
248: }
249: };
250:
251: public static final Field getPredicate = new Field() {
252: public Node getField(Triple t) {
253: return t.pred;
254: }
255:
256: public Filter filterOn(final Node n) {
257: return n.isConcrete() ? new Filter() {
258: public boolean accept(Object x) {
259: return n.equals(((Triple) x).pred);
260: }
261: } : Filter.any;
262: }
263: };
264: }
265: }
266:
267: /*
268: (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
269: All rights reserved.
270:
271: Redistribution and use in source and binary forms, with or without
272: modification, are permitted provided that the following conditions
273: are met:
274:
275: 1. Redistributions of source code must retain the above copyright
276: notice, this list of conditions and the following disclaimer.
277:
278: 2. Redistributions in binary form must reproduce the above copyright
279: notice, this list of conditions and the following disclaimer in the
280: documentation and/or other materials provided with the distribution.
281:
282: 3. The name of the author may not be used to endorse or promote products
283: derived from this software without specific prior written permission.
284:
285: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
286: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
287: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
288: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
289: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
290: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
291: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
292: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
293: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
294: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295: */
|