001: /*****************************************************************************
002: * Source code information
003: * -----------------------
004: * Original author Ian Dickinson, HP Labs Bristol
005: * Author email Ian.Dickinson@hp.com
006: * Package Jena 2
007: * Web http://sourceforge.net/projects/jena/
008: * Created 05-Jun-2003
009: * Filename $RCSfile: ResourceUtils.java,v $
010: * Revision $Revision: 1.16 $
011: * Release status $State: Exp $
012: *
013: * Last modified on $Date: 2008/01/02 12:07:44 $
014: * by $Author: andy_seaborne $
015: *
016: * (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
017: * (see footer for full conditions)
018: *****************************************************************************/package com.hp.hpl.jena.util;
019:
020: // Imports
021: ///////////////
022: import java.util.*;
023:
024: import com.hp.hpl.jena.rdf.model.*;
025:
026: /**
027: * <p>
028: * General utility methods that operate on RDF resources, but which are not specific
029: * to a given model.
030: * </p>
031: *
032: * @author Ian Dickinson, HP Labs
033: * (<a href="mailto:Ian.Dickinson@hp.com" >email</a>)
034: * @version CVS $Id: ResourceUtils.java,v 1.16 2008/01/02 12:07:44 andy_seaborne Exp $
035: */
036: public class ResourceUtils {
037: // Constants
038: //////////////////////////////////
039:
040: // Static variables
041: //////////////////////////////////
042:
043: // Instance variables
044: //////////////////////////////////
045:
046: // Constructors
047: //////////////////////////////////
048:
049: // External signature methods
050: //////////////////////////////////
051:
052: /**
053: * <p>
054: * Answer the maximal lower elements of the given collection, given the partial
055: * ordering <code>rel</code>. See {@link #maximalLowerElements( Iterator, Property, boolean )}
056: * for details.
057: * </p>
058: *
059: * @param resources A collection of resources
060: * @param rel A property defining a partial-ordering on <code>resources</code>
061: * @param inverse If true, we invert the given property (by reversing the order
062: * of the arguments), which allows us to use eg subClassOf as a partial order
063: * operator for both sub-class and super-class relationships
064: * @return The collection that contains only those <code>resources</code> are not
065: * greater than another resource under the partial order.
066: */
067: public static List maximalLowerElements(Collection resources,
068: Property rel, boolean inverse) {
069: return maximalLowerElements(resources.iterator(), rel, inverse);
070: }
071:
072: /**
073: * <p>
074: * Given a collection of resources, and a relation defining a partial order over
075: * those resources, answer the sub-collection that contains only those elements
076: * that appear in the maximal generator of the relation. Specifically, a resource
077: * <code>x</code> is excluded from the return value if there is another resource
078: * <code>y</code> in the input collection such that <code>y Rel x</code> holds.
079: * </p>
080: *
081: * @param resources An iterator over a collection of resources
082: * @param rel A property defining a partial-ordering on <code>resources</code>
083: * @param inverse If true, we invert the given property (by reversing the order
084: * of the arguments), which allows us to use eg subClassOf as a partial order
085: * operator for both sub-class and super-class relationships
086: * @return The list that contains only those <code>resources</code> are not
087: * greater than another resource under the partial order.
088: */
089: public static List maximalLowerElements(Iterator resources,
090: Property rel, boolean inverse) {
091: List in = new ArrayList();
092: List out = new ArrayList();
093: List drop = new ArrayList();
094:
095: while (resources.hasNext()) {
096: in.add(resources.next());
097: }
098:
099: while (!in.isEmpty()) {
100: Resource r = (Resource) in.remove(0);
101: boolean rCovered = testResourceCovered(in, rel, inverse, r)
102: || testResourceCovered(out, rel, inverse, r)
103: || testResourceCovered(drop, rel, inverse, r);
104:
105: // if r is not covered by another resource, we can add it to the output
106: (rCovered ? drop : out).add(r);
107: }
108:
109: return out;
110: }
111:
112: private static boolean testResourceCovered(List l, Property rel,
113: boolean inverse, Resource r) {
114: boolean rCovered = false;
115: for (Iterator i = l.iterator(); !rCovered && i.hasNext();) {
116: Resource next = (Resource) i.next();
117: rCovered = inverse ? r.hasProperty(rel, next) : next
118: .hasProperty(rel, r);
119: }
120: return rCovered;
121: }
122:
123: /**
124: * <p>Remove from the given list l of {@link Resource Resources}, any Resource that is equivalent
125: * to the reference resource <code>ref</code> under the relation <code>p</code>. Typically,
126: * <code>p</code> will be <code>owl:subClassOf</code> or <code>owl:subPropertyOf</code>
127: * or some similar predicate. A resource R is defined to be equivalent to <code>ref</code>
128: * iff <code>R p ref</code> is true <em>and</em> <code>ref p R</code> is true.
129: * </p>
130: * <p>The equivalent resources are removed from list <code>l</code>
131: * </em>in place</em>, the return value is the list of <em>removed</em> resources.</p>
132: * @param l A list of resources from which the resources equivalent to ref will be removed
133: * @param p An equivalence predicate
134: * @param ref A reference resource
135: * @return A list of the resources removed from the parameter list l
136: */
137: public static List removeEquiv(List l, Property p, Resource ref) {
138: List equiv = new ArrayList();
139:
140: for (Iterator i = l.iterator(); i.hasNext();) {
141: Resource r = (Resource) i.next();
142:
143: if (r.hasProperty(p, ref) && ref.hasProperty(p, r)) {
144: // resource r is equivalent to the reference resource
145: equiv.add(r);
146: }
147: }
148:
149: l.removeAll(equiv);
150: return equiv;
151: }
152:
153: /**
154: * <p>Answer a list of lists, which is a partition of the given
155: * input list of resources. The equivalence relation is the predicate p.
156: * So, two resources <code>a</code> and <code>b</code>
157: * will be in the same partition iff
158: * <code>(a p b) && (b p a)</code>.</p>
159: * @param l A list of resources
160: * @param p An equivalence predicate
161: * @return A list of lists which are the partitions of <code>l</code>
162: * under <code>p</code>
163: */
164: public static List partition(List l, Property p) {
165: // first copy the input so we can mess with it
166: List source = new ArrayList();
167: source.addAll(l);
168: List parts = new ArrayList();
169:
170: while (!source.isEmpty()) {
171: // each step through the loop we pick a random element, and
172: // create a list of that element and all its equivalent values
173: Resource seed = (Resource) source.remove(0);
174: List part = removeEquiv(source, p, seed);
175: part.add(seed);
176:
177: // add to the partition list
178: parts.add(part);
179: }
180:
181: return parts;
182: }
183:
184: /**
185: * <p>Answer a new resource that occupies the same position in the graph as the current
186: * resource <code>old</code>, but that has the given URI. In the process, the existing
187: * statements referring to <code>old</code> are removed. Since Jena does not allow the
188: * identity of a resource to change, this is the closest approximation to a rename operation
189: * that works.
190: * </p>
191: * <p><strong>Notes:</strong> This method does minimal checking, so renaming a resource
192: * to its own URI is unpredictable. Furthermore, it is a general and simple approach, and
193: * in given applications it may be possible to do this operation more efficiently. Finally,
194: * if <code>res</code> is a property, existing statements that use the property will not
195: * be renamed, nor will occurrences of <code>res</code> in other models.
196: * </p>
197: * @param old An existing resource in a given model
198: * @param uri A new URI for resource old, or null to rename old to a bNode
199: * @return A new resource that occupies the same position in the graph as old, but which
200: * has the new given URI.
201: */
202: public static Resource renameResource(Resource old, String uri) {
203: Model m = old.getModel();
204: List stmts = new ArrayList();
205:
206: // list the statements that mention old as a subject
207: for (Iterator i = old.listProperties(); i.hasNext(); stmts
208: .add(i.next()))
209: ;
210:
211: // list the statements that mention old an an object
212: for (Iterator i = m.listStatements(null, null, old); i
213: .hasNext(); stmts.add(i.next()))
214: ;
215:
216: // create a new resource to replace old
217: Resource res = (uri == null) ? m.createResource() : m
218: .createResource(uri);
219:
220: // now move the statements to refer to res instead of old
221: for (Iterator i = stmts.iterator(); i.hasNext();) {
222: Statement s = (Statement) i.next();
223:
224: s.remove();
225:
226: Resource subj = s.getSubject().equals(old) ? res : s
227: .getSubject();
228: RDFNode obj = s.getObject().equals(old) ? res : s
229: .getObject();
230:
231: m.add(subj, s.getPredicate(), obj);
232: }
233:
234: return res;
235: }
236:
237: /**
238: * <p>Answer a model that contains all of the resources reachable from a given
239: * resource by any property, transitively. The returned graph is the sub-graph
240: * of the parent graph of root, whose root node is the given root. Cycles are
241: * permitted in the sub-graph.</p>
242: * @param root The root node of the sub-graph to extract
243: * @return A model containing all reachable RDFNodes from root by any property.
244: */
245: public static Model reachableClosure(Resource root) {
246: Model m = ModelFactory.createDefaultModel();
247:
248: // set of resources we have passed through already (i.e. the occurs check)
249: Set seen = CollectionFactory.createHashedSet();
250:
251: // queue of resources we have not yet visited
252: List queue = new LinkedList();
253: queue.add(root);
254:
255: while (!queue.isEmpty()) {
256: Resource r = (Resource) queue.remove(0);
257:
258: // check for multiple paths arriving at this queue node
259: if (!seen.contains(r)) {
260: seen.add(r);
261:
262: // add the statements to the output model, and queue any new resources
263: for (StmtIterator i = r.listProperties(); i.hasNext();) {
264: Statement s = i.nextStatement();
265:
266: // don't do the occurs check now in case of reflexive statements
267: m.add(s);
268:
269: if (s.getObject() instanceof Resource) {
270: queue.add(s.getObject());
271: }
272: }
273: }
274: }
275:
276: return m;
277: }
278:
279: // Internal implementation methods
280: //////////////////////////////////
281:
282: //==============================================================================
283: // Inner class definitions
284: //==============================================================================
285:
286: }
287:
288: /*
289: (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
290: All rights reserved.
291:
292: Redistribution and use in source and binary forms, with or without
293: modification, are permitted provided that the following conditions
294: are met:
295:
296: 1. Redistributions of source code must retain the above copyright
297: notice, this list of conditions and the following disclaimer.
298:
299: 2. Redistributions in binary form must reproduce the above copyright
300: notice, this list of conditions and the following disclaimer in the
301: documentation and/or other materials provided with the distribution.
302:
303: 3. The name of the author may not be used to endorse or promote products
304: derived from this software without specific prior written permission.
305:
306: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
307: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
308: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
309: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
310: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
311: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
312: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
313: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
314: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
315: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
316: */
|