/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Package /////////////// package org.apache.jena.rdf.model; // Imports /////////////// import java.util.*; import java.util.function.Function; import org.apache.jena.util.iterator.* ; /** * <p> * Provides a convenience encapsulation for lists formed from chains of RDF * statements arranged to form a head/tail cons-cell structure. The properties * that form the links between cells, and from cells to values, are specified by * a vocabulary interface, so this abstraction is designed to cope equally well * with DAML lists, RDF lists, and user-defined lists. * </p> * <p> * A well-formed list has cells that are made up of three statements: one * denoting the <code>rdf:type</code> of the list cell, one denoting the link * to the value of the list at that point, and one pointing to the list tail. If * a list cell is not well-formed, list operations may fail in unpredictable * ways. However, to explicitly check that the list is well-formed at all times * is expensive. Therefore the list operates in two modes: in <i>strict</i> * mode, the well-formedness of the list is checked at the start of each list * operation, and an {@link InvalidListException} is thrown if the list is not * well- formed. This ensures that list operations are safe, but will slow down * processing. In <i>non-strict</i> mode, this checking is switched off, but can * be invoked explicitly by clients by calling {@link #isValid}. By default, RDF * lists are processed in non-strict mode. * </p> */ public interface RDFList extends Resource { // Constants ////////////////////////////////// // External signature methods ////////////////////////////////// /** * <p> * Answer the number of elements in the list. * </p> * * @return The size of the list as an integer */ public int size(); /** * <p> * Answer the value that is at the head of the list. * </p> * * @return The value that is associated with the head of the list. * @exception EmptyListException if this list is the empty list */ public RDFNode getHead(); /** * <p> * Update the head of the list to have the given value, and return the * previous value. * </p> * * @param value The value that will become the value of the list head * @exception EmptyListException if this list is the empty list */ public RDFNode setHead( RDFNode value ); /** * <p> * Answer the list that is the tail of this list. * </p> * * @return The tail of the list, as a list * @exception EmptyListException if this list is the empty list */ public RDFList getTail(); /** * <p> * Update the list cell at the front of the list to have the given list as * tail. The old tail is returned, and remains in the model. * </p> * * @param tail The new tail for this list. * @return The old tail. */ public RDFList setTail( RDFList tail ); /** * Answer true if this list is the empty list. * * @return True if this is the empty (nil) list, otherwise false. */ public boolean isEmpty(); /** * <p> * Return a reference to a new list cell whose head is <code>value</code> * and whose tail is this list. * </p> * * @param value A new value to add to the head of the list * @return The new list, whose head is <code>value</code> */ public RDFList cons( RDFNode value ); /** * <p> * Add the given value to the end of the list. This is a side-effecting * operation on the underlying model that is only defined if this is not the * empty list. If this list is the empty (nil) list, we cannot perform a * side-effecting update without changing the URI of this node (from <code>rdf:nil</code>) * to a blank-node for the new list cell) without violating a Jena invariant. * Therefore, this update operation will throw an exception if an attempt is * made to add to the nil list. Safe ways to add to an empty list include * {@link #with} and {@link #cons}. * </p> * * @param value A value to add to the end of the list * @exception EmptyListUpdateException if an attempt is made to * <code>add</code> to the empty list. */ public void add( RDFNode value ); /** * <p> * Answer the list that is this list with the given value added to the end * of the list. This operation differs from {@link #add} in that it will * always work, even on an empty list, but the return value is the updated * list. Specifically, in the case of adding a value to the empty list, the * returned list will not be the same as this list. <strong>Client code should * not assume that this is an in-place update, but should ensure that the resulting * list is asserted back into the graph into the appropriate relationships.</strong> * </p> * * @param value A value to add to the end of the list * @return The list that results from adding a value to the end of this list */ public RDFList with( RDFNode value ); /** * <p> * Answer the node that is the i'th element of the list, assuming that the * head is item zero. If the list is too short to have an i'th element, * throws a {@link ListIndexException}. * </p> * * @param i The index into the list, from 0 * @return The list value at index i, or null * @exception ListIndexException if the list has fewer than (i + 1) * elements. */ public RDFNode get( int i ); /** * <p> * Replace the value at the i'th position in the list with the given value. * If the list is too short to have an i'th element, throws a {@link * ListIndexException}. * </p> * * @param i The index into the list, from 0 * @param value The new value to associate with the i'th list element * @return The value that was previously at position i in the list * @exception ListIndexException if the list has fewer than (i + 1) * elements. */ public RDFNode replace( int i, RDFNode value ); /** * <p> * Answer true if the given node appears as the value of a value of any * of the cells of this list. * </p> * * @param value A value to test for * @return True if the list contains value. */ public boolean contains( RDFNode value ); /** * <p> * Answer the index of the first occurrence of the given value in the list, * or -1 if the value is not in the list. * </p> * * @param value The value to search for * @return The index of the first occurrence of value in the list, or * <code>-1</code> if not found. */ public int indexOf( RDFNode value ); /** * <p> * Answer the index of the first occurrence of the given value in the list * after index <code>start</code>, or -1 if the value is not in the list * after the given start point. * </p> * * @param value The value to search for * @param start The index into the list to start searching from * @return The index of the first occurrence of value in the list not less * than <code>start</code>, or <code>-1</code> if not found. * @exception ListIndexException if <code>start</code> is greater than the * length of the list. */ public int indexOf( RDFNode value, int start ); /** * <p> * Answer a new list that is formed by adding each element of this list to * the head of the given <code>list</code>. This is a non side-effecting * operation on either this list or the given list, but generates a copy * of this list. For a more storage efficient alternative, see {@link * #concatenate concatenate}. * </p> * * @param list The argument list * @return A new RDFList that contains all of this elements of this list, * followed by all of the elements of the given list. */ public RDFList append( RDFList list ); /** * <p> * Answer a new list that is formed by adding each element of this list to * the head of the the list formed from the * given <code>nodes</code>. This is a non side-effecting * operation on either this list or the given list, but generates a copy * of this list. For a more storage efficient alternative, see {@link * #concatenate concatenate}. * </p> * * @param nodes An iterator whose range is RDFNode * @return A new RDFList that contains all of this elements of this list, * followed by all of the elements of the given iterator. */ public RDFList append( Iterator<? extends RDFNode> nodes ); /** * <p> * Change the tail of this list to point to the given list, so that this * list becomes the list of the concatenation of the elements of both lists. * This is a side-effecting operation on this list; for a non side-effecting * alternative, see {@link #append}. Due to the problem of maintaining * the URI invariant on a node, this operation will throw an exception if an * attempt is made to concatenate onto an empty list. To avoid this, test for * an empty list: if true replace the empty list with the argument list, otherwise * proceed with the concatenate as usual. An alternative solution is to use * {@link #append} and replace the original list with the return value. * </p> * * @param list The argument list to concatenate to this list * @exception EmptyListUpdateException if this list is the nil list */ public void concatenate( RDFList list ); /** * <p> * Add the nodes returned by the given iterator to the end of this list. * </p> * * @param nodes An iterator whose range is RDFNode * @exception EmptyListUpdateException if this list is the nil list * @see #concatenate(RDFList) for details on avoiding the empty list update exception. */ public void concatenate( Iterator<? extends RDFNode> nodes ); /** * <p> * Answer a list that contains all of the elements of this list in the same * order, but is a duplicate copy in the underlying model. * </p> * * @return A copy of the current list */ public RDFList copy(); /** * <p> * Apply a function to each value in the list in turn. * </p> * * @param fn The function to apply to each list node. */ public void apply( ApplyFn fn ); /** * <p> * Apply a function to each value in the list in turn, accumulating the * results in an accumulator. The final value of the accumulator is returned * as the value of <code>reduce()</code>. * </p> * * @param fn The reduction function to apply * @param initial The initial value for the accumulator * @return The final value of the accumulator. */ public Object reduce( ReduceFn fn, Object initial ); /** * <p>Answer an iterator of the elements of this list, to each of which * the given map function has been applied.</p> * @param fn A mapping function * @return The iterator of the elements of this list mapped with the given map function. */ public <T> ExtendedIterator<T> mapWith( Function<RDFNode, T> fn ); /** * <p> * Remove the value from the head of the list. The tail of the list remains * in the model. Note that no changes are made to list cells that point to * this list cell as their tail. Immediately following a * <code>removeHead</code> operation, such lists will be in a non-valid * state. * </p> * * @return The remainder of the list after the head is removed (i.e. the * pre-removal list tail) */ public RDFList removeHead(); /** * <p>Deprecated. Since an <code>RDFList</code> does not behave like a Java container, it is not * the case that the contents of the list can be removed and the container filled with values * again. Therefore, this method name has been deprecated in favour of {@link #removeList}</p> * @deprecated Replaced by {@link #removeList} */ @Deprecated public void removeAll(); /** * <p>Remove all of the components of this list from the model. Once this operation * has completed, the {@link RDFList} resource on which it was called will no * longer be a resource in the model, so further methods calls on the list object * (for example, {@link #size} will fail. Due to restrictions on the encoding * of lists in RDF, it is not possible to perform an operation which empties a list * and then adds further values to that list. Client code wishing to perform * such an operation should do so in two steps: first remove the old list, then * create a new list with the new contents. It is important that RDF statements * that reference the old list (in the object position) be updated to point * to the newly created list. * Note that this * is operation is only removing the list cells themselves, not the resources * referenced by the list - unless being the object of an <code>rdf:first</code> * statement is the only mention of that resource in the model.</p> */ public void removeList(); /** * <p>Remove the given value from this list. If <code>val</code> does not occur in * the list, no action is taken. Since removing the head of the list will invalidate * the list head cell, in general the list must return the list that results from this * operation. However, in many cases the return value will be the same as the object * that this method is invoked on</p> * * @param val The value to be removed from the list * @return The resulting list, which will be the same as the current list in most * cases, except when <code>val</code> occurs at the head of the list. */ public RDFList remove( RDFNode val ); /** * <p> * Answer an iterator over the elements of the list. Note that this iterator * does not take a snapshot of the list, so changes to the list statements * in the model while iterating will affect the behaviour of the iterator. * To get an iterator that is not affected by model changes, use {@link * #asJavaList}. * </p> * * @return A closable iterator over the elements of the list. */ public ExtendedIterator<RDFNode> iterator(); /** * <p> * Answer the contents of this RDF list as a Java list of RDFNode values. * </p> * * @return The contents of this list as a Java List. */ public List<RDFNode> asJavaList(); /** * <p> * Answer true if this list has the same elements in the same order as the * given list. Note that the standard <code>equals</code> test just tests * for equality of two given list cells. While such a test is sufficient * for many purposes, this test provides a broader equality definition, but * is correspondingly more expensive to test. * </p> * * @param list The list to test against * @return True if the given list and this list are the same length, and * contain equal elements in the same order. */ public boolean sameListAs( RDFList list ); /** * <p> * Answer true lists are operating in strict mode, in which the * well- formedness of the list is checked at every operation. * </p> * * @return True lists are being strictly checked. */ public boolean getStrict(); /** * <p> * Set a flag to indicate whether to strictly check the well-formedness of * lists at each operation. Default false. <strong>Note</strong> that the flag that is * manipulated is actually a static: it applies to all lists. However, RDFList * is a Java interface, and Java does not permit static methods in interfaces. * </p> * * @param strict The <b>static</b> flag for whether lists will be checked strictly. */ public void setStrict( boolean strict ); /** * <p> * Answer true if the list is well-formed, by checking that each node is * correctly typed, and has a head and tail pointer from the correct * vocabulary. If the list is invalid, the reason is available via {@link * #getValidityErrorMessage}. * </p> * * @return True if the list is well-formed. * @see #getValidityErrorMessage */ public boolean isValid(); /** * <p> * Answer the error message returned by the last failed validity check, * if any. * </p> * * @return The most recent error message, or null. * @see #isValid */ public String getValidityErrorMessage(); //============================================================================== // Inner class definitions //============================================================================== /** * Interface that encapsulates a function to apply to every element in a * list. */ public static interface ApplyFn { /** * <p> * Apply a function to the given RDF node. * </p> * * @param node A node from the list. */ public void apply( RDFNode node ); } /** * Interface that encapsulates a function to apply to each element of a list * in turn, and passing the result to an accumulator. */ public static interface ReduceFn { /** * <p> * Apply a function to the given RDF node. * </p> * * @param node A node from the list. * @param accumulator The accumulator for the reduction, which will * either be an initial value passed to {@link RDFList#reduce}, or the * output from <code>reduce</code> applied to the previous node in the * list. * @return The result of applying the reduction function to the current * node and the accumulator. */ public Object reduce( RDFNode node, Object accumulator ); } }