001: /*
002: (c) Copyright 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP, all rights reserved.
003: [See end of file]
004: $Id: SimpleReifierFragmentsMap.java,v 1.23 2008/01/02 12:05:17 andy_seaborne Exp $
005: */
006: package com.hp.hpl.jena.graph.impl;
007:
008: import java.util.Iterator;
009: import java.util.Map;
010: import java.util.Set;
011:
012: import com.hp.hpl.jena.graph.*;
013: import com.hp.hpl.jena.util.CollectionFactory;
014: import com.hp.hpl.jena.util.iterator.*;
015: import com.hp.hpl.jena.vocabulary.RDF;
016:
017: /**
018: SimpleReifierFragmentsMap - a map from nodes to the incompleteb(or
019: overcomplete) reification quadlets.
020:
021: @author kers
022: */
023: public class SimpleReifierFragmentsMap implements ReifierFragmentsMap {
024: protected Map forwardMap = CollectionFactory.createHashedMap();
025:
026: protected Fragments getFragments(Node tag) {
027: return (Fragments) forwardMap.get(tag);
028: }
029:
030: protected void removeFragments(Node key) {
031: forwardMap.remove(key);
032: }
033:
034: public void clear() {
035: forwardMap.clear();
036: }
037:
038: /**
039: update the map with (node -> fragment); return the fragment.
040: */
041: protected Fragments putFragments(Node key, Fragments value) {
042: forwardMap.put(key, value);
043: return value;
044: }
045:
046: protected ExtendedIterator allTriples(TripleMatch tm) {
047: if (forwardMap.isEmpty())
048: return NullIterator.instance;
049: Triple t = tm.asTriple();
050: Node subject = t.getSubject();
051: if (subject.isConcrete()) {
052: Fragments x = (Fragments) forwardMap.get(subject);
053: return x == null ? NullIterator.instance
054: : explodeFragments(t, subject, x);
055: } else {
056: final Iterator it = forwardMap.entrySet().iterator();
057: return new FragmentTripleIterator(t, it) {
058: public void fill(GraphAdd ga, Node n,
059: Object fragmentsObject) {
060: ((Fragments) fragmentsObject).includeInto(ga);
061: }
062: };
063: }
064: }
065:
066: /**
067: * @param t
068: * @param subject
069: * @param x
070: * @return
071: */
072: protected ExtendedIterator explodeFragments(Triple t, Node subject,
073: Fragments x) {
074: GraphAddList L = new GraphAddList(t);
075: x.includeInto(L);
076: return WrappedIterator.create(L.iterator());
077: }
078:
079: public ExtendedIterator find(TripleMatch m) {
080: return allTriples(m);
081: }
082:
083: public int size() {
084: int result = 0;
085: Iterator it = forwardMap.entrySet().iterator();
086: while (it.hasNext()) {
087: Map.Entry e = (Map.Entry) it.next();
088: Fragments f = (Fragments) e.getValue();
089: result += f.size();
090: }
091: return result;
092: }
093:
094: /**
095: given a triple t, see if it's a reification triple and if so return the internal selector;
096: otherwise return null.
097: */
098: public ReifierFragmentHandler getFragmentHandler(Triple t) {
099: Node p = t.getPredicate();
100: ReifierFragmentHandler x = (ReifierFragmentHandler) selectors
101: .get(p);
102: if (x == null
103: || (p.equals(RDF.Nodes.type) && !t.getObject().equals(
104: RDF.Nodes.Statement)))
105: return null;
106: return x;
107: }
108:
109: public void putAugmentedTriple(SimpleReifierFragmentHandler s,
110: Node tag, Node object, Triple reified) {
111: Fragments partial = new Fragments(tag, reified);
112: partial.add(s, object);
113: putFragments(tag, partial);
114: }
115:
116: protected Triple reifyCompleteQuad(SimpleReifierFragmentHandler s,
117: Triple fragment, Node tag, Node object) {
118: Fragments partial = getFragments(tag);
119: if (partial == null)
120: putFragments(tag, partial = new Fragments(tag));
121: partial.add(s, object);
122: if (partial.isComplete()) {
123: removeFragments(fragment.getSubject());
124: return partial.asTriple();
125: } else
126: return null;
127: }
128:
129: protected Triple removeFragment(SimpleReifierFragmentHandler s,
130: Node tag, Triple already, Triple fragment) {
131: Fragments partial = getFragments(tag);
132: Fragments fs = (already != null ? explode(tag, already)
133: : partial == null ? putFragments(tag,
134: new Fragments(tag)) : (Fragments) partial);
135: fs.remove(s, fragment.getObject());
136: if (fs.isComplete()) {
137: Triple result = fs.asTriple();
138: removeFragments(tag);
139: return result;
140: } else {
141: if (fs.isEmpty())
142: removeFragments(tag);
143: return null;
144: }
145: }
146:
147: protected Fragments explode(Node s, Triple t) {
148: return putFragments(s, new Fragments(s, t));
149: }
150:
151: public boolean hasFragments(Node tag) {
152: return getFragments(tag) != null;
153: }
154:
155: protected static class Fragments {
156:
157: /**
158: a Fragments object is represented by four sets, one for each of the reification
159: predicates. The slots are array elements because, sadly, it's easier to dynamically
160: choose a slot by number than any other way I could think of.
161: */
162: private final Set[] slots = {
163: CollectionFactory.createHashedSet(),
164: CollectionFactory.createHashedSet(),
165: CollectionFactory.createHashedSet(),
166: CollectionFactory.createHashedSet() };
167:
168: /**
169: the Node the fragments are about.
170: */
171: private Node anchor;
172:
173: /**
174: a fresh Fragments object remembers the node n and starts
175: off with all sets empty. (In use, at least one of the slots will
176: then immediately be updated - otherwise there was no reason
177: to create the Fragments in the first place ...)
178: */
179: public Fragments(Node n) {
180: this .anchor = n;
181: }
182:
183: public Fragments(Node n, Triple t) {
184: this (n);
185: addTriple(t);
186: }
187:
188: public int size() {
189: return slots[0].size() + slots[1].size() + slots[2].size()
190: + slots[3].size();
191: }
192:
193: /**
194: true iff this is a complete fragment; every component is present with exactly
195: one value, so n unambiguously reifies (subject, predicate, object).
196: */
197: public boolean isComplete() {
198: return slots[0].size() == 1 && slots[1].size() == 1
199: && slots[2].size() == 1 && slots[3].size() == 1;
200: }
201:
202: /**
203: true iff this is an empty fragment; no reificational assertions have been made
204: about n. (Hence, in use, the Fragments object can be discarded.)
205: */
206: public boolean isEmpty() {
207: return slots[0].isEmpty() && slots[1].isEmpty()
208: && slots[2].isEmpty() && slots[3].isEmpty();
209: }
210:
211: /**
212: remove the node n from the set specified by slot which.
213: */
214: public void remove(SimpleReifierFragmentHandler w, Node n) {
215: slots[w.which].remove(n);
216: }
217:
218: /**
219: add the node n to the slot identified by which).
220: */
221: public void add(SimpleReifierFragmentHandler w, Node n) {
222: slots[w.which].add(n);
223: }
224:
225: /**
226: include into g all of the reification components that this Fragments
227: represents.
228: */
229: public void includeInto(GraphAdd g) {
230: includeInto(g, RDF.Nodes.subject, SUBJECTS_index);
231: includeInto(g, RDF.Nodes.predicate, PREDICATES_index);
232: includeInto(g, RDF.Nodes.object, OBJECTS_index);
233: includeInto(g, RDF.Nodes.type, TYPES_index);
234: }
235:
236: /**
237: include into g all of the (n, p[which], o) triples for which
238: o is an element of the slot <code>which</code> corresponding to
239: predicate.
240: */
241: private void includeInto(GraphAdd g, Node predicate, int which) {
242: Iterator it = slots[which].iterator();
243: while (it.hasNext())
244: g.add(Triple
245: .create(anchor, predicate, (Node) it.next()));
246: }
247:
248: /**
249: add to this Fragments the entire reification quad needed to
250: reify the triple t.
251: @param t: Triple the (S, P, O) triple to reify
252: @return this with the quad for (S, P, O) added
253: */
254: public Fragments addTriple(Triple t) {
255: slots[SUBJECTS_index].add(t.getSubject());
256: slots[PREDICATES_index].add(t.getPredicate());
257: slots[OBJECTS_index].add(t.getObject());
258: slots[TYPES_index].add(RDF.Nodes.Statement);
259: return this ;
260: }
261:
262: /**
263: precondition: isComplete()
264: <p>
265: return the single Triple that this Fragments represents; only legal if
266: isComplete() is true.
267: */
268: Triple asTriple() {
269: return Triple.create(only(slots[SUBJECTS_index]),
270: only(slots[PREDICATES_index]),
271: only(slots[OBJECTS_index]));
272: }
273:
274: /**
275: precondition: s.size() == 1
276: <p>
277: utiltity method to return the only element of a singleton set.
278: */
279: private Node only(Set s) {
280: return (Node) s.iterator().next();
281: }
282:
283: /**
284: return a readable representation of this Fragment for debugging purposes.
285: */
286: public String toString() {
287: return anchor + " s:" + slots[SUBJECTS_index] + " p:"
288: + slots[PREDICATES_index] + " o:"
289: + slots[OBJECTS_index] + " t:" + slots[TYPES_index];
290: }
291:
292: }
293:
294: /*
295: the magic numbers for the slots. The order doesn't matter, but that they're
296: some permutation of {0, 1, 2, 3} does.
297: */
298: protected static final int TYPES_index = 0;
299: protected static final int SUBJECTS_index = 1;
300: protected static final int PREDICATES_index = 2;
301: protected static final int OBJECTS_index = 3;
302:
303: protected final ReifierFragmentHandler TYPES = new SimpleReifierFragmentHandler(
304: this , TYPES_index) {
305: public boolean clashesWith(ReifierFragmentsMap map, Node n,
306: Triple reified) {
307: return false;
308: }
309: };
310: protected final ReifierFragmentHandler SUBJECTS = new SimpleReifierFragmentHandler(
311: this , SUBJECTS_index) {
312: public boolean clashesWith(ReifierFragmentsMap map, Node n,
313: Triple reified) {
314: return !n.equals(reified.getSubject());
315: }
316: };
317: protected final ReifierFragmentHandler PREDICATES = new SimpleReifierFragmentHandler(
318: this , PREDICATES_index) {
319: public boolean clashesWith(ReifierFragmentsMap map, Node n,
320: Triple reified) {
321: return !n.equals(reified.getPredicate());
322: }
323: };
324: protected final ReifierFragmentHandler OBJECTS = new SimpleReifierFragmentHandler(
325: this , OBJECTS_index) {
326: public boolean clashesWith(ReifierFragmentsMap map, Node n,
327: Triple reified) {
328: return !n.equals(reified.getObject());
329: }
330: };
331:
332: public final Map selectors = makeSelectors();
333:
334: /**
335: make the selector mapping.
336: */
337: protected Map makeSelectors() {
338: Map result = CollectionFactory.createHashedMap();
339: result.put(RDF.Nodes.subject, SUBJECTS);
340: result.put(RDF.Nodes.predicate, PREDICATES);
341: result.put(RDF.Nodes.object, OBJECTS);
342: result.put(RDF.Nodes.type, TYPES);
343: return result;
344: }
345: }
346:
347: /*
348: (c) Copyright 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
349: All rights reserved.
350:
351: Redistribution and use in source and binary forms, with or without
352: modification, are permitted provided that the following conditions
353: are met:
354:
355: 1. Redistributions of source code must retain the above copyright
356: notice, this list of conditions and the following disclaimer.
357:
358: 2. Redistributions in binary form must reproduce the above copyright
359: notice, this list of conditions and the following disclaimer in the
360: documentation and/or other materials provided with the distribution.
361:
362: 3. The name of the author may not be used to endorse or promote products
363: derived from this software without specific prior written permission.
364:
365: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
366: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
367: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
368: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
369: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
370: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
371: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
372: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
374: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
375: */
|