1 /*********************************************************************
2 Copyright 2012, Ralph Ronnquist.
4 This file is part of GORITE.
6 GORITE is free software: you can redistribute it and/or modify it
7 under the terms of the Lesser GNU General Public License as published
8 by the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GORITE is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the Lesser GNU General Public
17 License along with GORITE. If not, see <http://www.gnu.org/licenses/>.
18 **********************************************************************/
20 package com.intendico.data;
22 import java.util.HashSet;
23 import java.util.Hashtable;
24 import java.util.Iterator;
25 import java.util.Observable;
26 import java.util.Observer;
27 import java.util.Vector;
30 * A Relation is a set of tuples of the same size. It is created by
31 * enumerating the types of its columns.
33 * <p> A relation may have one or more <em>key constraints</em>. A key
34 * constraint combines one or more fields into a <em>key</em>, which
35 * the relation may hold only one tuple for any combination of
36 * values. The key constraints are used by the {@link #add} method,
37 * such that addition of a new tuple may cause the removal of prior
38 * tuples that are equal in some key combination of fields.
40 * <p> A relation is modified via the {@link #add} and {@link #remove}
41 * methods. Both of these notify observers if the relation is changed.
43 * <p> A relation can be queried via the {@link #query} method, which
44 * returns an {@link java.util.Iterator} for the matching tuples, or
45 * by the {@link #get} method, which instead returns a {@link
46 * Relation.Cursor} that implements the {@link Query} interface.
48 public class Relation extends Observable implements Store, Inquirable {
51 * Utility method to create a copy of an object array. Only the
52 * array is copied, not its values.
54 public static Object [] copyArray(Object[] in)
56 Object [] out = new Object [ in.length ];
57 System.arraycopy( in, 0, out, 0, in.length);
62 * An instance name for this relation.
64 public final String name;
67 * The required field types.
69 public final Class [] column_types;
72 * The special key pattern for all fields being key.
74 public final KeyPattern main_key;
77 * Holds the relation data in a layered structure. First hash
78 * index is the key pattern, and second hash index is the key (of
79 * a pattern). Actual data is a HashSet of Tuple objects, which
80 * are compared by using {@link java.lang.Object#equals} of their
83 public Hashtable/*<KeyPattern,Hashtable<Tuple,HashSet<Tuple>>>*/ indexes =
84 new Hashtable/*<KeyPattern,Hashtable<Tuple,HashSet<Tuple>>>*/();
87 * Holds the collection of constraining key patterns. When a tuple
88 * is added, any already existing tuple of the same key (according
89 * to any constraining key pattern) is seen as an opposing tuple,
90 * which is removed (without observer notification).
92 public HashSet/*<KeyPattern>*/ constraints;
95 * The ArityException is thrown when a relation is accessed with a
96 * wrong number of fields.
98 public class ArityException extends Exception {
101 * Version identity required for serialization.
103 public static final long serialVersionUID = 1L;
106 * Telling the required number of fields.
108 public final int requires;
111 * Telling the given number of fields.
113 public final int attempted;
118 public ArityException(int r,int a) {
125 * The ColumnTypeException exception is thrown when a realtion is
126 * accessed by means of wrong field types.
128 public class ColumnTypeException extends Exception {
131 * Version identity required for serialization.
133 public static final long serialVersionUID = 1L;
136 * The required type of the first erroneous field.
138 public final Class requires;
141 * The given type of the first erroneous field.
143 public final Class attempted;
148 public final int index;
153 public ColumnTypeException(int i,Class r,Class a) {
161 * Constructor. This defines both the relation arity and the
162 * individual types of the fields.
164 public Relation(String n,Class/*...*/ [] types) {
166 column_types = types;
167 main_key = new KeyPattern();
171 * Alternative constructor with name and arity only.
173 public Relation(String n,int arity) {
175 column_types = new Class [ arity ];
176 for ( int i = 0; i < arity; i++ ) {
177 column_types[ i ] = Object.class;
179 main_key = new KeyPattern();
183 * Clears the relation, i.e. removes all its tuples. Its key
184 * constraints are unchanged.
186 public void clear() {
188 new Hashtable/*<KeyPattern,Hashtable<Tuple,HashSet<Tuple>>>*/();
194 * Returning an Observable that notifies about subsequent changes
197 public Observable getMonitor() {
202 * Adds a constraining key pattern. The relation is managed to
203 * allow at most one tuple of any key of the constraining key
204 * patterns. This is enforced when new tuples are added, which
205 * thus results in that a prior tuple of the same key is removed
206 * (without observer notification).
208 * <p> Note that a relation that violates the key constraint when
209 * the constraint is added will not be corrected until an opposing
210 * tuple is added. It does make good sense to add all key
211 * constraints before any tuples are added.
213 public Relation addConstraint(boolean/*...*/ [] pattern)
214 throws ArityException
216 if ( constraints == null )
217 constraints = new HashSet/*<KeyPattern>*/();
218 constraints.add( new KeyPattern( pattern ) );
223 * Removes a constraining key pattern.
225 * <p> Note that the general advice is <em>aginst</em> removing
226 * key constraints, but rather creating a new relation with the
227 * reduced set of constraints and then populate that.
229 public void removeConstraint(boolean/*...*/ [] pattern)
230 throws ArityException
232 if ( constraints == null )
234 constraints.remove( new KeyPattern( pattern ) );
235 if ( constraints.size() == 0 )
240 * Utility method to remove all tuples opposed to a given tuple
241 * according to a given key pattern. Tuples are removed without
242 * observer notification.
244 public void applyConstraint(KeyPattern constraint,Tuple adding)
245 throws ArityException, ColumnTypeException
247 Tuple key = constraint.getKey( adding );
248 for ( Iterator/*<Tuple>*/ i = query( key ); i.hasNext(); ) {
249 addPending( (Tuple) i.next() );
251 processPending( false );
255 * Utility method to remove all tuples that are opposite to the
256 * given tuple with respect to the constraining key patterns.
257 * Tuples are removed without observer notification.
259 public void applyConstraints(Tuple adding)
260 throws ArityException, ColumnTypeException
262 if ( constraints == null )
264 for ( Iterator/*<KeyPattern>*/ i =
265 constraints.iterator(); i.hasNext(); ) {
266 applyConstraint( (KeyPattern) i.next(), adding );
271 * Utility method that investigates that fields are appropriate
272 * for the relation. Any violations are reported by throwing the
273 * appropriate exception.
274 * @throws ArityException if there is a wrong number of fields.
275 * @throws ColumnTypeException if any field is of wrong type.
277 public void runtimeTyping(Object/*...*/ [] fields)
278 throws ArityException, ColumnTypeException
280 if ( column_types == null ) {
281 if ( fields == null )
283 throw new ArityException( 0, fields.length );
286 if ( fields == null )
287 throw new ArityException( column_types.length, 0 );
289 if ( fields.length != column_types.length )
290 throw new ArityException( column_types.length, fields.length );
292 for ( int i = 0; i < fields.length; i++ ) {
293 Object x = Ref.deref( fields[ i ] );
296 if ( column_types[ i ].isInstance( x ) )
298 throw new ColumnTypeException(
299 i, column_types[ i ], x.getClass() );
305 * Represents an I/O key pattern for the relation. This is used
306 * for identifying keyed access tables.
308 public class KeyPattern {
311 * The I/O pattern expressed as a boolean array. A true means
312 * input, and a false means output.
317 * Constructor by boolean indicators. True indicates an input
318 * field, and false indicates an output field.
320 public KeyPattern(boolean/*...*/ [] io)
321 throws ArityException
323 if ( io.length != column_types.length )
324 throw new ArityException( column_types.length, io.length );
329 * Default constructor, with all fields key fields.
331 public KeyPattern() {
332 pattern = new boolean[ column_types.length ];
333 for ( int i = 0; i < pattern.length; i++ )
334 pattern[ i ] = false;
338 * Constructor by field presence. The constructor is called
339 * with the right number of fields, leaving output fields as
340 * null and input fields non-null.
342 public KeyPattern(Object/*...*/ [] io)
343 throws ArityException
345 if ( io.length != column_types.length )
346 throw new ArityException( column_types.length, io.length );
347 // check types as well?
348 pattern = new boolean [ io.length ];
349 for ( int i = 0; i < io.length; i++ )
350 pattern[ i ] = Ref.deref( io[ i ] ) != null;
354 * Equality of KeyPattern objects is determined by comparing
355 * their boolean patterns.
357 public boolean equals(Object p) {
358 return p instanceof KeyPattern ? equals( (KeyPattern) p ) : false ;
362 * Equality of KeyPattern objects is determined by comparing
363 * their boolean patterns.
365 public boolean equals(KeyPattern p) {
366 if ( pattern == null || p.pattern == null )
367 return pattern == null && p.pattern == null;
368 if ( pattern.length != p.pattern.length )
370 for ( int i = 0; i < pattern.length; i++ )
371 if ( pattern[ i ] != p.pattern[ i ] )
377 * The hashCode of a KeyPattern is derived by treating its
378 * boolean pattern as a bit pattern.
380 public int hashCode() {
382 for ( int i = 0; i < pattern.length; i++ )
383 code = ( code << 1 ) + ( pattern[ i ]? 1 : 0 );
388 * Returns a tuple by projecting the given tuple through this
391 public Tuple getKey(Tuple t) {
392 return new Tuple( t, pattern );
396 * Returns a String representation of the KeyPattern object.
398 public String toString() {
399 StringBuffer s = new StringBuffer();
401 for ( int i = 0; i < pattern.length; i++ ) {
403 s.append( pattern[ i ] );
406 return "KeyPattern(" + s.toString() +")";
411 * Representation of relation row. In a contents row, all fields
412 * of a tuple should be non-<em>null</em>. Tuples that represent
413 * access patterns typically have <em>null</em>-valued {@link Ref}
414 * objects, or are <em>null</em> directly, for the output fields,
415 * whereas the input fields provide values to match with.
420 * Holds the field values.
422 public Object [] fields;
428 fields = new Object[ column_types.length ];
434 public Tuple(Object/*...*/ [] tuple) {
435 fields = copyArray( tuple );
439 * Returns the number of <em>null</em> fields of this tuple.
441 public int nullCount() {
443 for (int i = 0; i < fields.length; i++) {
444 if ( Ref.deref( fields[ i ] ) == null )
451 * Key constructor. Creates a copy of the given tuple, but
452 * clears the output fields, as given by the key pattern.
454 public Tuple(Tuple t,boolean [] pattern) {
456 for (int i = 0; i < fields.length; i++) {
458 fields[ i ] = Ref.deref( t.fields[ i ] );
459 else if ( fields[ i ] instanceof Ref )
460 ((Ref) fields[ i ]).clear();
465 * Utility method to clear this tuple according to the key
468 public void clear(boolean [] pattern) {
469 for ( int i = 0; i < pattern.length; i++ ) {
472 if ( fields[ i ] instanceof Ref )
473 ((Ref) fields[ i ] ).clear();
480 * Determine whether a given query matches this tuple, by
481 * comparing all non-null query fields with the tuple fields
482 * using the equals method.
484 * @return <em>true</em> if this tuple matches the given query
485 * tuple when ignoring its <em>null</em> fields, and
486 * <em>false</em> otherwise.
488 public boolean match(Tuple query) {
489 for ( int i = 0; i < fields.length; i++ ) {
490 Object x = Ref.deref( query.fields[ i ] );
493 if ( ! x.equals( Ref.deref( fields[ i ] ) ) )
500 * Fill in the fields of a query from this tuple using the
503 //@SuppressWarnings("unchecked")
504 public void getFields(KeyPattern kp, Object [] output) {
505 for ( int i = 0; i < fields.length; i++ ) {
506 if ( ! kp.pattern[ i ] ) {
507 if ( output[ i ] instanceof Ref )
508 ((Ref) output[ i ]).set( fields[ i ] );
510 output[ i ] = fields[ i ];
516 * Returns a given field value.
518 public Object getField(int index) {
519 return fields[ index ];
523 * Determine whether this tuple is equal to a given object.
525 public boolean equals(Object x) {
526 return x instanceof Tuple? equals( (Tuple) x ) : false;
530 * Determine whether this tuple is equal to another. The
531 * method dereferences any {@link Ref} objects of both this
532 * tuple and the other tuple.
534 * @return <em>true</em> if all field values (after
535 * dereference) are equal, and <em>false</em> otherwise.
537 public boolean equals(Tuple x) {
538 for ( int i = 0; i < fields.length; i++ ) {
540 Ref.deref( fields[ i ] ),
541 Ref.deref( x.fields[ i ] ) ) )
548 * Utility method to compare field values that may be
551 * @return <em>true</em> if the field values are equal, and
552 * <em>false</em> otherwise.
554 public boolean equalFields(Object a,Object b) {
555 return ( a == null || b == null )? a == b : a.equals( b );
559 * Compute a tuple hash code, by combining the dereferenced
560 * field values in a deterministic way.
562 * <p> Note that tuples may have the same hash code without
565 * @return the hash code.
567 public int hashCode() {
569 for ( int i = 0; i < fields.length; i++ ) {
571 x += ( Ref.deref( fields[ i ] ) == null?
573 Ref.deref( fields[ i ] ).hashCode() );
579 * Support method to queue up this tuple for removal from its
580 * relation. Use method {@link #processPending} to process
583 * <p> This method is intended to simplify the combination of
584 * iterating over several tuples of the relation while
585 * removing some of them, without this causing problems due to
586 * {@link java.util.ConcurrentModificationException} being
587 * thrown. (Please refer to notes about {@link
588 * java.util.HashSet}).
590 public void delayedRemove() {
595 * Returns a String representation of this tuple.
597 public String toString() {
598 StringBuffer s = new StringBuffer("<");
599 for ( int i = 0; i < fields.length; i++ ) {
602 s.append( fields[ i ] == null? "null" : fields[ i ].toString() );
609 * Utility method to collect Ref objects in the fields.
611 public Vector/*<Ref>*/ getRefs(Vector/*<Ref>*/ v) {
612 for ( int i = 0; i < fields.length; i++ ) {
613 if ( fields[ i ] instanceof Ref ) {
614 Ref r = (Ref) fields[ i ];
615 if ( ! v.contains( r ) )
625 * Utility method for accessing the data table of a key pattern
628 public HashSet/*<Tuple>*/ getData(KeyPattern kp,Tuple tuple,boolean add) {
629 Hashtable/*<Tuple,HashSet<Tuple>>*/ table =
630 (Hashtable/*<Tuple,HashSet<Tuple>>*/) indexes.get( kp );
631 if ( table == null ) {
632 table = new Hashtable/*<Tuple,HashSet<Tuple>>*/();
633 indexes.put( kp, table );
635 Tuple key = kp.getKey( tuple );
636 HashSet/*<Tuple>*/ data = (HashSet/*<Tuple>*/) table.get( key );
637 if ( add && data == null ) {
638 data = new HashSet/*<Tuple>*/();
639 table.put( key, data );
645 * Utility method to obtain an iterator over existing key
648 public Iterator/*<KeyPattern>*/ keyPatterns() {
649 return indexes.keySet().iterator();
653 * Access method to add a tuple to the relation. Returns false if
654 * the relation already contains the tuple. Otherwise all tables
655 * are updated, and the method returns true.
657 * <p> Note that all values a dereferenced before being added to
660 * @return <em>true</em> if the relation is changed, and
661 * <em>false</em> otherwise.
663 * @see #runtimeTyping
666 synchronized public boolean add(Object/*...*/ [] values)
667 throws ArityException, ColumnTypeException
669 runtimeTyping( values );
671 for ( int i=0; i < values.length; i++ )
672 values[ i ] = Ref.deref( values[ i ] );
674 Tuple tuple = new Tuple( values );
676 HashSet/*<Tuple>*/ data = getData( main_key, tuple, true );
677 if ( data.contains( tuple ) ) {
681 applyConstraints( tuple );
683 for (Iterator/*<KeyPattern>*/ kpi = keyPatterns(); kpi.hasNext(); ) {
684 getData( (KeyPattern) kpi.next(), tuple, true ).add( tuple );
693 * Access method to remove a tuple from the relation. Returns
694 * false if the tuple is missing from the relation. Otherwise all
695 * tables are updated, and the method returns true.
697 * @see #runtimeTyping
700 synchronized public boolean remove(Object/*...*/ [] values)
701 throws ArityException, ColumnTypeException
703 if ( removeQuietly( values ) ) {
712 * Internal working method to remove tuples without notifying any
713 * observer. The remove function is split up in this way in order
714 * to allow the {@link #add} method to apply the key constraints
715 * without notifications of key constraint knock-outs.
717 public boolean removeQuietly(Object/*...*/ [] values)
718 throws ArityException, ColumnTypeException
720 runtimeTyping( values );
721 Tuple tuple = new Tuple( values );
723 HashSet/*<Tuple>*/ data = getData( main_key, tuple, true );
724 if ( !data.contains( tuple ) )
727 for (Iterator/*<KeyPattern>*/ kpi = keyPatterns(); kpi.hasNext(); ) {
728 getData( (KeyPattern) kpi.next(), tuple, true ).remove( tuple );
734 * Returns the size of the relation, i.e., the number of key
735 * tuples in the {@link #main_key} collection.
737 synchronized public int size() {
738 Hashtable/*<Tuple,HashSet<Tuple>>*/ table =
739 (Hashtable/*<Tuple,HashSet<Tuple>>*/) indexes.get( main_key );
740 return table == null? 0 : table.size();
744 * Returns the projected size of the relation, i.e., the number of
745 * tuples matching to the tuple of the given values, with null
746 * values (or unbound Ref objects) indicating non-key columns.
748 public int size(Object/*...*/ [] values) {
749 return size( new Tuple( values ) );
753 * Returns the projected size of the relation, i.e., the number of
754 * tuples matching to the given key tuple.
756 synchronized public int size(Tuple key) {
758 KeyPattern kp = new KeyPattern( key.fields );
759 if ( indexes.get( kp ) == null ) {
762 HashSet/*<Tuple>*/ data = getData( kp, key, false );
763 return data == null? 0 : data.size();
764 } catch (Exception e) {
771 * Utility method to populate a HashSet matching to a key
773 public void populate(KeyPattern kp)
775 Hashtable/*<Tuple,HashSet<Tuple>>*/ table =
776 new Hashtable/*<Tuple,HashSet<Tuple>>*/();
777 indexes.put( kp, table );
778 HashSet/*<Tuple>*/ db = getData( main_key, new Tuple(), true );
779 for ( Iterator/*<Tuple>*/ i = db.iterator(); i.hasNext(); ) {
780 Tuple t = (Tuple) i.next();
781 HashSet/*<Tuple>*/ data = getData( kp, kp.getKey( t ), true );
787 * Utility method to obtain an Iterator for the tuple set that
788 * matches the given key values.
790 public Iterator/*<Tuple>*/ query(Object/*...*/ [] values)
791 throws ArityException, ColumnTypeException
793 runtimeTyping( values );
794 Tuple key = new Tuple( values );
799 * Utility method to obtain an Iterator for the tuple set that
800 * matches the given key tuple.
802 synchronized public Iterator/*<Tuple>*/ query(Tuple key)
803 throws ArityException, ColumnTypeException
805 KeyPattern kp = new KeyPattern( key.fields );
806 if ( indexes.get( kp ) == null ) {
809 HashSet/*<Tuple>*/ data = getData( kp, key, true );
810 return data.iterator();
814 * The Cursor class provides Query processing support for a
817 public class Cursor implements Query {
820 * A {@link Relation.Tuple} object that is updated for new
826 * The querying key pattern.
828 public KeyPattern key_pattern;
831 * The result iterator.
833 public Iterator/*<Tuple>*/ current;
836 * Constructor for key values. Output fields are marked by
837 * {@link Ref} objects of <em>null</em> values, and ignored
838 * fields are marked by <em>null</em>.
840 public Cursor(Object/*...*/ [] values)
841 throws ArityException, ColumnTypeException
843 output = new Tuple( values );
844 key_pattern = new KeyPattern( output.fields );
849 * The {@link Query#copy} method implemented by creating a new
850 * Cursor with new {@link Ref} objects.
852 //@SuppressWarnings("unchecked")
853 public Query copy(Vector/*<Ref>*/ newrefs) throws Exception {
854 Object [] fields = copyArray( output.fields );
855 for ( int i = 0; i < fields.length; i++ ) {
856 if ( fields[ i ] instanceof Ref ) {
857 fields[ i ] = ((Ref) fields[ i ]).find( newrefs );
860 return new Cursor( fields );
864 * The {@link Query#reset} method implemented by recomputing
865 * the key pattern and the matching tuple set.
868 throws ArityException, ColumnTypeException
870 key_pattern = new KeyPattern( output.fields );
871 current = query( key_pattern.getKey( output ) );
875 * The {@link Query#next} method implemented by binding the
876 * output {@link Ref} objects for the next match.
878 public boolean next() {
879 if ( ! current.hasNext() ) {
880 output.clear( key_pattern.pattern );
883 ((Tuple) current.next()).getFields( key_pattern, output.fields );
888 * The {@link Query#getRefs} method implemented by returning the
889 * {@link Ref} objects given to this Cursor object.
891 public Vector/*<Ref>*/ getRefs(Vector/*<Ref>*/ v) {
892 return output.getRefs( v );
896 * The {@link Query#addObserver} method implemented by adding
897 * the observer to the relation.
899 public void addObserver(Observer x) {
900 Relation.this.addObserver( x );
904 * The {@link Query#deleteObserver} method implemented by
905 * removing the observer from the relation.
907 public void deleteObserver(Observer x) {
908 Relation.this.deleteObserver( x );
912 * Implements the {@link Query#addable} method by verifying
913 * that all {@link Ref} objects are non-<em>null</em>.
915 public boolean addable()
917 return output.nullCount() == 0;
921 * The {@link Query#add} method implemented by adding to
922 * current output tuple to the relation, provided that all its
923 * {@link Ref} objects are non-<em>null</em>.
928 if ( output.nullCount() == 0 ) {
929 Object [] fields = new Object [ output.fields.length ];
931 output.fields, 0, fields, 0, fields.length );
932 return Relation.this.add( fields );
934 } catch (Exception e) {
936 System.err.println( "** ignored **" );
942 * Implements {@link Query#removable} by checking that the
943 * indicated tuple is stored.
945 public boolean removable() {
946 HashSet/*<Tuple>*/ data = getData( main_key, output, true );
947 return data.contains( output );
951 * Implements {@link Query#remove} by removing the indicated
954 * @return <em>true</em> if tuple was removed, and
955 * <em>false</em> otherwise.
957 public boolean remove() {
959 return Relation.this.remove( output.fields );
960 } catch (Exception e) {
967 * Returns a {link java.lang.String} representation of this
968 * Cursor. This uses the {@link Relation#name} field as well
969 * as the {@link Ref#name} field of any {@link Ref} object
970 * involved (both input and output).
972 public String toString() {
973 StringBuffer s = new StringBuffer();
974 s.append( Relation.this.name );
976 for ( int i = 0; i < output.fields.length; i++ ) {
980 if ( output.fields[ i ] instanceof Ref ) {
981 s.append( ((Ref) output.fields[ i ] ).getName() );
984 s.append( output.fields[ i ] );
993 * An interface method to obtain a {@link Query} implementation
994 * object, {@link Relation.Cursor} for given key. The output
995 * fields would be marked by <em>null</em> valued {@link Ref}
996 * objects, which get successively assigned for the matching
999 public Query get(Object/*...*/ [] values) throws Exception {
1000 return new Cursor( values );
1004 * Interface method to obtain the Inquirable name.
1006 public String getName() {
1011 // Pending removal support
1015 * Transient support for delayed removal of tuples.
1017 public HashSet/*<Tuple>*/ pending;
1020 * Adds a tuple to the pending table.
1022 * @see Relation.Tuple#delayedRemove
1024 synchronized public void addPending(Tuple t) {
1025 if ( pending == null )
1026 pending = new HashSet/*<Tuple>*/();
1031 * Utility method to remove all pending tuples. Invokes {@link
1032 * #processPending(boolean)} with argument <em>true</em>.
1033 * @return <em>true</em> if the relation is changed, and
1034 *<em>false</em> otherwise.
1036 * @return <em>true</em> if the relation is changed, and
1037 * <em>false</em> otherwise.
1039 * @see #processPending(boolean)
1041 synchronized public boolean processPending()
1043 return processPending( true );
1047 * Utility method to remove all pending tuples. The noise argument
1048 * marks whether (<em>true</em>) or not (<em>false</em>) to notify
1049 * observers if the relation is changed.
1051 * @return <em>true</em> if the relation is changed, and
1052 *<em>false</em> otherwise.
1054 * @see #removeQuietly
1056 synchronized public boolean processPending(boolean noise)
1058 if ( pending == null )
1060 boolean removed = false;
1061 for ( Iterator/*<Tuple>*/ i = pending.iterator(); i.hasNext(); ) {
1063 removed |= removeQuietly( ((Tuple) i.next()).fields );
1064 } catch (Exception e) {
1065 System.err.println( "processPending: " + e.toString() );
1069 if ( noise && removed ) {
1077 /// Convenience methods
1081 * Convenience method for unary relation key constraint setting.
1083 public void addConstraint(boolean x)
1084 throws ArityException {
1085 addConstraint( new boolean [] { x } );
1089 * Convenience method for unary relation assertion.
1091 public boolean add(Object x)
1092 throws ArityException, ColumnTypeException {
1093 return add( new Object [] { x } );
1097 * Convenience method for unary relation retraction.
1099 public boolean remove(Object x)
1100 throws ArityException, ColumnTypeException {
1101 return remove( new Object [] { x } );
1106 * Convenience method for binary relation key constraint setting.
1108 public void addConstraint(boolean x1,boolean x2)
1109 throws ArityException {
1110 addConstraint( new boolean [] { x1, x2 } );
1114 * Convenience method for binary relation assertion.
1116 public boolean add(Object x1,Object x2)
1117 throws ArityException, ColumnTypeException {
1118 return add( new Object [] { x1, x2 } );
1122 * Convenience method for binary relation retraction.
1124 public boolean remove(Object x1,Object x2)
1125 throws ArityException, ColumnTypeException {
1126 return remove( new Object [] { x1, x2 } );
1131 * Convenience method for tertiary relation key constraint setting.
1133 public void addConstraint(boolean x1,boolean x2,boolean x3)
1134 throws ArityException {
1135 addConstraint( new boolean [] { x1, x2, x3 } );
1139 * Convenience method for tertiary relation assertion.
1141 public boolean add(Object x1,Object x2,Object x3)
1142 throws ArityException, ColumnTypeException {
1143 return add( new Object [] { x1, x2, x3 } );
1147 * Convenience method for tertiary relation retraction.
1149 public boolean remove(Object x1,Object x2,Object x3)
1150 throws ArityException, ColumnTypeException {
1151 return remove( new Object [] { x1, x2, x3 } );
1155 * Returns a String representation of this relation.
1157 public String toString() {
1158 return indexes.toString();