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 24 Jan 2003
009: * Filename $RCSfile: RDFList.java,v $
010: * Revision $Revision: 1.13 $
011: * Release status @releaseStatus@ $State: Exp $
012: *
013: * Last modified on $Date: 2008/01/02 12:05:46 $
014: * by $Author: andy_seaborne $
015: *
016: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
017: * (see footer for full conditions)
018: *****************************************************************************/package com.hp.hpl.jena.rdf.model;
019:
020: // Imports
021: ///////////////
022: import com.hp.hpl.jena.util.iterator.*;
023:
024: import java.util.*;
025:
026: /**
027: * <p>
028: * Provides a convenience encapsulation for lists formed from chains of RDF
029: * statements arranged to form a head/tail cons-cell structure. The properties
030: * that form the links between cells, and from cells to values, are specified by
031: * a vocabulary interface, so this abstraction is designed to cope equally well
032: * with DAML lists, RDF lists, and user-defined lists.
033: * </p>
034: * <p>
035: * A well-formed list has cells that are made up of three statements: one
036: * denoting the <code>rdf:type</code> of the list cell, one denoting the link
037: * to the value of the list at that point, and one pointing to the list tail. If
038: * a list cell is not well-formed, list operations may fail in unpredictable
039: * ways. However, to explicitly check that the list is well-formed at all times
040: * is expensive. Therefore the list operates in two modes: in <i>strict</i>
041: * mode, the well-formedness of the list is checked at the start of each list
042: * operation, and an {@link InvalidListException} is thrown if the list is not
043: * well- formed. This ensures that list operations are safe, but will slow down
044: * processing. In <i>non-strict</i> mode, this checking is switched off, but can
045: * be invoked explicitly by clients by calling {@link #isValid}. By default, RDF
046: * lists are processed in non-strict mode.
047: * </p>
048: *
049: * @author Ian Dickinson, HP Labs
050: * (<a href="mailto:Ian.Dickinson@hp.com" >email</a>)
051: * @version Release ($Id: RDFList.java,v 1.13 2008/01/02 12:05:46 andy_seaborne Exp $)
052: */
053: public interface RDFList extends Resource {
054: // Constants
055: //////////////////////////////////
056:
057: // External signature methods
058: //////////////////////////////////
059:
060: /**
061: * <p>
062: * Answer the number of elements in the list.
063: * </p>
064: *
065: * @return The size of the list as an integer
066: */
067: public int size();
068:
069: /**
070: * <p>
071: * Answer the value that is at the head of the list.
072: * </p>
073: *
074: * @return The value that is associated with the head of the list.
075: * @exception EmptyListException if this list is the empty list
076: */
077: public RDFNode getHead();
078:
079: /**
080: * <p>
081: * Update the head of the list to have the given value, and return the
082: * previous value.
083: * </p>
084: *
085: * @param value The value that will become the value of the list head
086: * @exception EmptyListException if this list is the empty list
087: */
088: public RDFNode setHead(RDFNode value);
089:
090: /**
091: * <p>
092: * Answer the list that is the tail of this list.
093: * </p>
094: *
095: * @return The tail of the list, as a list
096: * @exception EmptyListException if this list is the empty list
097: */
098: public RDFList getTail();
099:
100: /**
101: * <p>
102: * Update the list cell at the front of the list to have the given list as
103: * tail. The old tail is returned, and remains in the model.
104: * </p>
105: *
106: * @param tail The new tail for this list.
107: * @return The old tail.
108: */
109: public RDFList setTail(RDFList tail);
110:
111: /**
112: * Answer true if this list is the empty list.
113: *
114: * @return True if this is the empty (nil) list, otherwise false.
115: */
116: public boolean isEmpty();
117:
118: /**
119: * <p>
120: * Return a reference to a new list cell whose head is <code>value</code>
121: * and whose tail is this list.
122: * </p>
123: *
124: * @param value A new value to add to the head of the list
125: * @return The new list, whose head is <code>value</code>
126: */
127: public RDFList cons(RDFNode value);
128:
129: /**
130: * <p>
131: * Add the given value to the end of the list. This is a side-effecting
132: * operation on the underlying model that is only defined if this is not the
133: * empty list. If this list is the empty (nil) list, we cannot perform a
134: * side-effecting update without changing the URI of this node (from <code>rdf:nil</code)
135: * to a blank-node for the new list cell) without violating a Jena invariant.
136: * Therefore, this update operation will throw an exception if an attempt is
137: * made to add to the nil list. Safe ways to add to an empty list include
138: * {@link #with} and {@link #cons}.
139: * </p>
140: *
141: * @param value A value to add to the end of the list
142: * @exception EmptyListUpdateException if an attempt is made to
143: * <code>add</code> to the empty list.
144: */
145: public void add(RDFNode value);
146:
147: /**
148: * <p>
149: * Answer the list that is this list with the given value added to the end
150: * of the list. This operation differs from {@link #add} in that it will
151: * always work, even on an empty list, but the return value is the updated
152: * list. Specifically, in the case of adding a value to the empty list, the
153: * returned list will not be the same as this list. <strong>Client code should
154: * not assume that this is an in-place update, but should ensure that the resulting
155: * list is asserted back into the graph into the appropriate relationships.</strong>
156: * </p>
157: *
158: * @param value A value to add to the end of the list
159: * @return The list that results from adding a value to the end of this list
160: */
161: public RDFList with(RDFNode value);
162:
163: /**
164: * <p>
165: * Answer the node that is the i'th element of the list, assuming that the
166: * head is item zero. If the list is too short to have an i'th element,
167: * throws a {@link ListIndexException}.
168: * </p>
169: *
170: * @param i The index into the list, from 0
171: * @return The list value at index i, or null
172: * @exception ListIndexException if the list has fewer than (i + 1)
173: * elements.
174: */
175: public RDFNode get(int i);
176:
177: /**
178: * <p>
179: * Replace the value at the i'th position in the list with the given value.
180: * If the list is too short to have an i'th element, throws a {@link
181: * ListIndexException}.
182: * </p>
183: *
184: * @param i The index into the list, from 0
185: * @param value The new value to associate with the i'th list element
186: * @return The value that was previously at position i in the list
187: * @exception ListIndexException if the list has fewer than (i + 1)
188: * elements.
189: */
190: public RDFNode replace(int i, RDFNode value);
191:
192: /**
193: * <p>
194: * Answer true if the given node appears as the value of a value of any
195: * of the cells of this list.
196: * </p>
197: *
198: * @param value A value to test for
199: * @return True if the list contains value.
200: */
201: public boolean contains(RDFNode value);
202:
203: /**
204: * <p>
205: * Answer the index of the first occurrence of the given value in the list,
206: * or -1 if the value is not in the list.
207: * </p>
208: *
209: * @param value The value to search for
210: * @return The index of the first occurrence of value in the list, or
211: * <code>-1</code> if not found.
212: */
213: public int indexOf(RDFNode value);
214:
215: /**
216: * <p>
217: * Answer the index of the first occurrence of the given value in the list
218: * after index <code>start</code>, or -1 if the value is not in the list
219: * after the given start point.
220: * </p>
221: *
222: * @param value The value to search for
223: * @param start The index into the list to start searching from
224: * @return The index of the first occurrence of value in the list not less
225: * than <code>start</code>, or <code>-1</code> if not found.
226: * @exception ListIndexException if <code>start</code> is greater than the
227: * length of the list.
228: */
229: public int indexOf(RDFNode value, int start);
230:
231: /**
232: * <p>
233: * Answer a new list that is formed by adding each element of this list to
234: * the head of the given <code>list</code>. This is a non side-effecting
235: * operation on either this list or the given list, but generates a copy
236: * of this list. For a more storage efficient alternative, see {@link
237: * #concatenate concatenate}.
238: * </p>
239: *
240: * @param list The argument list
241: * @return A new RDFList that contains all of this elements of this list,
242: * followed by all of the elements of the given list.
243: */
244: public RDFList append(RDFList list);
245:
246: /**
247: * <p>
248: * Answer a new list that is formed by adding each element of this list to
249: * the head of the the list formed from the
250: * given <code>nodes</code>. This is a non side-effecting
251: * operation on either this list or the given list, but generates a copy
252: * of this list. For a more storage efficient alternative, see {@link
253: * #concatenate concatenate}.
254: * </p>
255: *
256: * @param nodes An iterator whose range is RDFNode
257: * @return A new RDFList that contains all of this elements of this list,
258: * followed by all of the elements of the given iterator.
259: */
260: public RDFList append(Iterator nodes);
261:
262: /**
263: * <p>
264: * Change the tail of this list to point to the given list, so that this
265: * list becomes the list of the concatenation of the elements of both lists.
266: * This is a side-effecting operation on this list; for a non side-effecting
267: * alternative, see {@link #append}. Due to the problem of maintaining
268: * the URI invariant on a node, this operation will throw an exception if an
269: * attempt is made to concatenate onto an empty list. To avoid this, test for
270: * an empty list: if true replace the empty list with the argument list, otherwise
271: * proceed with the concatenate as usual. An alternative solution is to use
272: * {@link #append} and replace the original list with the return value.
273: * </p>
274: *
275: * @param list The argument list to concatenate to this list
276: * @exception EmptyListUpdateException if this list is the nil list
277: */
278: public void concatenate(RDFList list);
279:
280: /**
281: * <p>
282: * Add the nodes returned by the given iterator to the end of this list.
283: * </p>
284: *
285: * @param nodes An iterator whose range is RDFNode
286: * @exception EmptyListUpdateException if this list is the nil list
287: * @see #concatenate(RDFList) for details on avoiding the empty list update exception.
288: */
289: public void concatenate(Iterator nodes);
290:
291: /**
292: * <p>
293: * Answer a list that contains all of the elements of this list in the same
294: * order, but is a duplicate copy in the underlying model.
295: * </p>
296: *
297: * @return A copy of the current list
298: */
299: public RDFList copy();
300:
301: /**
302: * <p>
303: * Apply a function to each value in the list in turn.
304: * </p>
305: *
306: * @param fn The function to apply to each list node.
307: */
308: public void apply(ApplyFn fn);
309:
310: /**
311: * <p>
312: * Apply a function to each value in the list in turn, accumulating the
313: * results in an accumulator. The final value of the accumulator is returned
314: * as the value of <code>reduce()</code>.
315: * </p>
316: *
317: * @param fn The reduction function to apply
318: * @param initial The initial value for the accumulator
319: * @return The final value of the accumulator.
320: */
321: public Object reduce(ReduceFn fn, Object initial);
322:
323: /**
324: * <p>Answer an iterator of the elements of this list, to each of which
325: * the given map function has been applied.</p>
326: * @param fn A Map function
327: * @return The iterator of the elements of this list mapped with the given map function.
328: */
329: public ExtendedIterator mapWith(Map1 fn);
330:
331: /**
332: * <p>
333: * Remove the value from the head of the list. The tail of the list remains
334: * in the model. Note that no changes are made to list cells that point to
335: * this list cell as their tail. Immediately following a
336: * <code>removeHead</code> operation, such lists will be in a non-valid
337: * state.
338: * </p>
339: *
340: * @return The remainder of the list after the head is removed (i.e. the
341: * pre-removal list tail)
342: */
343: public RDFList removeHead();
344:
345: /**
346: * <p>Deprecated. Since an <code>RDFList</code> does not behave like a Java container, it is not
347: * the case that the contents of the list can be removed and the container filled with values
348: * again. Therefore, this method name has been deprecated in favour of {@link #removeList}</p>
349: * @deprecated Replaced by {@link #removeList}
350: */
351: public void removeAll();
352:
353: /**
354: * <p>Remove all of the components of this list from the model. Once this operation
355: * has completed, the {@link RDFList} resource on which it was called will no
356: * longer be a resource in the model, so further methods calls on the list object
357: * (for example, {@link #size} will fail. Due to restrictions on the encoding
358: * of lists in RDF, it is not possible to perform an operation which empties a list
359: * and then adds further values to that list. Client code wishing to perform
360: * such an operation should do so in two steps: first remove the old list, then
361: * create a new list with the new contents. It is important that RDF statements
362: * that reference the old list (in the object position) be updated to point
363: * to the newly created list.
364: * Note that this
365: * is operation is only removing the list cells themselves, not the resources
366: * referenced by the list - unless being the object of an <code>rdf:first</code>
367: * statement is the only mention of that resource in the model.</p>
368: */
369: public void removeList();
370:
371: /**
372: * <p>Remove the given value from this list. If <code>val</code> does not occur in
373: * the list, no action is taken. Since removing the head of the list will invalidate
374: * the list head cell, in general the list must return the list that results from this
375: * operation. However, in many cases the return value will be the same as the object
376: * that this method is invoked on</p>
377: *
378: * @param val The value to be removed from the list
379: * @return The resulting list, which will be the same as the current list in most
380: * cases, except when <code>val</code> occurs at the head of the list.
381: */
382: public RDFList remove(RDFNode val);
383:
384: /**
385: * <p>
386: * Answer an iterator over the elements of the list. Note that this iterator
387: * does not take a snapshot of the list, so changes to the list statements
388: * in the model while iterating will affect the behaviour of the iterator.
389: * To get an iterator that is not affected by model changes, use {@link
390: * #asJavaList}.
391: * </p>
392: *
393: * @return A closable iterator over the elements of the list.
394: */
395: public ExtendedIterator iterator();
396:
397: /**
398: * <p>
399: * Answer the contents of this RDF list as a Java list of RDFNode values.
400: * </p>
401: *
402: * @return The contents of this list as a Java List.
403: */
404: public List asJavaList();
405:
406: /**
407: * <p>
408: * Answer true if this list has the same elements in the same order as the
409: * given list. Note that the standard <code>equals</code> test just tests
410: * for equality of two given list cells. While such a test is sufficient
411: * for many purposes, this test provides a broader equality definition, but
412: * is correspondingly more expensive to test.
413: * </p>
414: *
415: * @param list The list to test against
416: * @return True if the given list and this list are the same length, and
417: * contain equal elements in the same order.
418: */
419: public boolean sameListAs(RDFList list);
420:
421: /**
422: * <p>
423: * Answer true lists are operating in strict mode, in which the
424: * well- formedness of the list is checked at every operation.
425: * </p>
426: *
427: * @return True lists are being strictly checked.
428: */
429: public boolean getStrict();
430:
431: /**
432: * <p>
433: * Set a flag to indicate whether to strictly check the well-formedness of
434: * lists at each operation. Default false. <strong>Note</strong> that the flag that is
435: * manipulated is actually a static: it applies to all lists. However, RDFList
436: * is a Java interface, and Java does not permit static methods in interfaces.
437: * </p>
438: *
439: * @param strict The <b>static</b> flag for whether lists will be checked strictly.
440: */
441: public void setStrict(boolean strict);
442:
443: /**
444: * <p>
445: * Answer true if the list is well-formed, by checking that each node is
446: * correctly typed, and has a head and tail pointer from the correct
447: * vocabulary. If the list is invalid, the reason is available via {@link
448: * #getValidityErrorMessage}.
449: * </p>
450: *
451: * @return True if the list is well-formed.
452: * @see #getValidityErrorMessage
453: */
454: public boolean isValid();
455:
456: /**
457: * <p>
458: * Answer the error message returned by the last failed validity check,
459: * if any.
460: * </p>
461: *
462: * @return The most recent error message, or null.
463: * @see #isValid
464: */
465: public String getValidityErrorMessage();
466:
467: //==============================================================================
468: // Inner class definitions
469: //==============================================================================
470:
471: /**
472: * Interface that encapsulates a function to apply to every element in a
473: * list.
474: */
475: public static interface ApplyFn {
476: /**
477: * <p>
478: * Apply a function to the given RDF node.
479: * </p>
480: *
481: * @param node A node from the list.
482: */
483: public void apply(RDFNode node);
484: }
485:
486: /**
487: * Interface that encapsulates a function to apply to each element of a list
488: * in turn, and passing the result to an accumulator.
489: */
490: public static interface ReduceFn {
491: /**
492: * <p>
493: * Apply a function to the given RDF node.
494: * </p>
495: *
496: * @param node A node from the list.
497: * @param accumulator The accumulator for the reduction, which will
498: * either be an initial value passed to {@link RDFList#reduce}, or the
499: * output from <code>reduce</code> applied to the previous node in the
500: * list.
501: * @return The result of applying the reduction function to the current
502: * node and the accumulator.
503: */
504: public Object reduce(RDFNode node, Object accumulator);
505: }
506: }
507:
508: /*
509: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
510: All rights reserved.
511:
512: Redistribution and use in source and binary forms, with or without
513: modification, are permitted provided that the following conditions
514: are met:
515:
516: 1. Redistributions of source code must retain the above copyright
517: notice, this list of conditions and the following disclaimer.
518:
519: 2. Redistributions in binary form must reproduce the above copyright
520: notice, this list of conditions and the following disclaimer in the
521: documentation and/or other materials provided with the distribution.
522:
523: 3. The name of the author may not be used to endorse or promote products
524: derived from this software without specific prior written permission.
525:
526: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
527: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
528: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
529: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
530: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
531: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
532: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
533: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
534: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
535: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
536: */
|