View Javadoc
1   package eu.simuline.util;
2   
3   import java.lang.reflect.Array;
4   
5   import java.util.List;
6   import java.util.Iterator;
7   import java.util.Spliterator; // for javadoc only 
8   import java.util.ListIterator;
9   import java.util.Collections;
10  import java.util.Collection;
11  import java.util.AbstractCollection;
12  import java.util.ArrayList;
13  import java.util.Set;
14  import java.util.SortedSet;
15  import java.util.Comparator;
16  import java.util.WeakHashMap;
17  import java.util.EnumSet;
18  import java.util.Map;
19  
20  import java.util.stream.Stream; // for javadoc only 
21  
22  import java.util.function.Predicate;
23  import java.util.function.Consumer;
24  import java.util.function.UnaryOperator;
25  import java.util.NavigableMap;
26  
27  /**
28   * An add on of the core class {@link java.util.Collections}. 
29   * This class provides various kinds of immutable collections, 
30   * where immutability is configurable 
31   * via a {@link CollectionsExt.Modification} object. 
32   * <p>
33   * Also this class yields weak hash sets via {@link #weakHashSet()}. 
34   * Moreover, there are methods to convert arrays and lists in one another 
35   * also recursively. 
36   * Finally, there are methods {@link #getUnique(Collection)} 
37   * to retrieve the unique element and {@link #reverse(List)}
38   * reverses a list. 
39   *
40   * @param <E>
41   *    the class of the elements of collections under consideration. 
42   *
43   * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
44   * @version 1.0
45   */
46  public abstract class CollectionsExt<E> {
47  
48      /* -------------------------------------------------------------------- *
49       * inner classes.                                                       *
50       * -------------------------------------------------------------------- */
51  
52      /**
53       * Enumerates the kinds of modifications on a {@link Collection}. 
54       * A collection is modified either directly or via its iterator's 
55       * method {@link Iterator#remove()}. 
56       * The direct modifications split in adding and removing a single object, 
57       * clearing the whole collection 
58       * and bulk operations like adding, removing, retaining 
59       * all objects which are in another {@link Collection}. 
60       * Subinterfaces of {@link Collection} 
61       * may offer further kinds of modifications: 
62       * {@link SortedSet}s for example define views on the original set 
63       * 
64       */
65      public enum Modification {
66  	/**
67  	 * Modification adding an element 
68  	 * which may be by {@link Collection#add(Object)}, 
69  	 * {@link Collection#addAll(Collection)},  
70  	 * by {@link List#add(int, Object)}, 
71  	 * {@link List#addAll(int, Collection)}, 
72  	 * <p>
73  . 	 * Modification by {@link ListIterator#add(Object)} 
74  	 * of (list)-iterator attached with underlying {@link List} 
75  	 * via {@link List#listIterator()} or {@link List#listIterator(int)}. 
76  	 */
77  	AddObj, 
78  
79  	/**
80  	 * Modification by {@link Collection#remove(Object)}, 
81  	 * {@link Collection#removeAll(Collection)}, 
82  	 * {@link Collection#retainAll(Collection)}, 
83  	 * {@link Collection#removeIf(Predicate)}, 
84  	 * {@link Collection#clear()} 
85  	 * and by {@link List#remove(int)}. 
86  	 * <p>
87  	 * Modification by {@link Iterator#remove()} 
88  	 * of iterator attached with underlying {@link Collection} 
89  	 * via {@link Collection#iterator()}, {@link List#listIterator()} 
90  	 * or {@link List#listIterator(int)}. 
91  	 */
92  	RemoveObj, 
93  
94  	/**
95  	 * Modification by {@link List#set(int, Object)}, 
96  	 * {@link List#replaceAll(UnaryOperator)} and 
97  	 * {@link List#sort(Comparator)}. 
98  	 * <p>
99  	 * Modification by {@link ListIterator#set(Object)} 
100 	 * of iterator attached with underlying {@link List} 
101 	 * via {@link List#listIterator()} or {@link List#listIterator(int)}. 
102 	 */
103 	SetObj;
104     } // enum Modification 
105 
106     /**
107      * A class of {@link Collection}s of elements of class <code>E</code>
108      * extending <code>C</code> 
109      * initially throwing an <code>UnsupportedOperationException</code> 
110      * when trying to modify the collection 
111      * either directly or via its iterator(s) 
112      * or via a transparent view 
113      * like {@link List#subList(int, int)}. 
114      * Note that neither arrays given e.g. by {@link Collection#toArray()} 
115      * nor {@link Spliterator}s given by {@link Collection#spliterator()} 
116      * nor {@link Stream}s given by {@link Collection#parallelStream()} 
117      * give no rise to modifications of the underlying collection. 
118      * **** currently, replacing (done for lists, e.g.), 
119      * is not considered a modification but the objects are transformed... 
120      * very esotheric... 
121      * **** what must be done is overwrite the default implementation. 
122      * Since it is not clear whether the wrapped collection did also overwrite, 
123      * it is not clear which kind of operation is done. 
124      * Thus it seems appropriate to define another kind of modification: 
125      * SetAll
126 
127      * New releases of the jdk may add default methods to interfaces 
128      * and may thus add ways to modify a list. 
129      * The problem is not so much a default implementation of the interface 
130      * since this is based on elementary methods of that interface 
131      * but if a class overwrites this 
132      * using internal methods or direct access to fields. 
133      * In particular, a each default method must be reimplemented: 
134      * E.g. {@link Collection#removeIf(Predicate)} 
135      * uses method {@link Collection#remove(Object)} 
136      * but it is possible to implement {@link Collection#removeIf(Predicate)} 
137      * without invoking {@link Collection#remove(Object)} 
138      * in implementations of implementing classes of {@link Collection}. 
139      * 
140      * it is possible, although not likely, 
141      * that 
142 
143 
144      * <p>
145      * Instances of this class can be created via creator methods like 
146      * {@link #getImmutableCollection(Collection)}. 
147      * The collection with the original restrictions can be regained 
148      * by {@link #unrestricted()}. 
149      * A posteriory modifications can be allowed 
150      * using {@link #allowModification(CollectionsExt.Modification)} or 
151      * using {@link #allowModifications(Set)}. 
152      * This class is <code>public</code> 
153      * and {@link #getImmutableCollection(Collection)} 
154      * returns instances of this class, to allow invoking methods 
155      * {@link #allowModification(CollectionsExt.Modification)} and 
156      * {@link #allowModifications(Set)}. 
157      * <p>
158      * Methods defining non-modifying access, 
159      * are just delegated to the collection 
160      * returned by {@link #unrestricted()}, 
161      * whereas methods for modification are blocked 
162      * if the modification is not allowed according to 
163      * {@link #allowedModifications()}. 
164      *
165      * @param <C>
166      *    the class extending {@link Collection} with elements in E. 
167      * @param <E>
168      *    the class of the elements of this collection. 
169      */
170     public abstract static 
171 	class AbstractImmutableCollection<C extends Collection<E>, E> 
172 	extends AbstractCollection<E> {
173 
174     	private static final long serialVersionUID = -2479143000061671589L;
175 
176     	/* ---------------------------------------------------------------- *
177     	 * fields.                                                          *
178     	 * ---------------------------------------------------------------- */
179 
180 	/**
181 	 * The set of allowed modifications. 
182 	 */
183     	private final Set<Modification> mods;
184 
185     	/* ---------------------------------------------------------------- *
186     	 * constructors.                                                    *
187     	 * ---------------------------------------------------------------- */
188 
189 	/**
190 	 * Creates an empty collection with no allowed modifications. 
191 	 *
192 	 * @see #CollectionsExt.AbstractImmutableCollection(Set)
193 	 */
194     	private AbstractImmutableCollection() {
195    	    this(EnumSet.noneOf(Modification.class));
196     	}
197 
198 	/**
199 	 * Creates an empty collection with the allowed modifications 
200 	 * given by <code>mods</code>. 
201 	 * CAUTION: This is not a collection containing <code>mods</code>. 
202 	 *
203 	 * @param mods
204 	 *    The modifications currently allowed. 
205 	 */
206     	AbstractImmutableCollection(Set<Modification> mods) {
207    	    this.mods = mods;
208     	}
209 
210     	/* ---------------------------------------------------------------- *
211     	 * methods.                                                         *
212     	 * ---------------------------------------------------------------- */
213 
214 	/**
215 	 * Allows in addition modification <code>mod</code> 
216 	 * for this set, does not alter contents and returns <code>this</code>. 
217 	 *
218 	 * @param mod
219 	 *    A modification which shall be allowed in addition. 
220 	 */
221     	public final AbstractImmutableCollection<C, E> 
222 	    allowModification(Modification mod) {
223     	    this.mods.add(mod);
224     	    return this;
225     	}
226 
227 	/**
228 	 * Allows in addition modifications in <code>mods</code> 
229 	 * for this set, does not alter contents and returns <code>this</code>. 
230 	 *
231 	 * @param mods
232 	 *    modifications which shall be allowed in addition. 
233 	 */
234     	public final void allowModifications(Set<Modification> mods) {
235     	    this.mods.addAll(mods);
236     	}
237 
238 	// This method allows handling modifications more tightly 
239 	// so that the other methods are mere convenience methods. 
240 	/**
241 	 * Returns the set of allowed modification of this set 
242 	 * without backup: Changing the returned set 
243 	 * changes the allowed modifications for this set. 
244 	 * Also applying {@link #allowModifications(Set)} 
245 	 * modifies the returned set. 
246 	 *
247 	 * @return
248 	 *    the set of currently allowed modifications. 
249 	 */
250     	public final Set<Modification> allowedModifications() {
251     	    return this.mods;
252     	}
253 
254 	/**
255 	 * Returns the underlying set without the restrictions 
256 	 * imposed by this {@link CollectionsExt.ImmutableCollection}. 
257 	 * Note that the result 
258 	 * may still throw {@link UnsupportedOperationException}s 
259 	 * depending on the implementation. 
260 	 */
261 	public abstract C unrestricted();
262 
263 	// from iterable 
264 	// forEach 
265 
266 	// query operations 
267 
268 	// iterator comes below 
269 
270 	/**
271 	 * Returns the size of this collection. 
272 	 */
273 	public final int size() {
274 	    return unrestricted().size();
275 	}
276 
277 	// inherited from AbstractCollection: 
278 	// isEmpty() 
279 	// boolean contains(Object o) 
280 	// Object[] toArray() 
281 	// T[] toArray(T[] a) 
282 
283 
284 	// Modification Operations
285 
286      	/**
287     	 * @throws UnsupportedOperationException
288 	 *    if either {@link #unrestricted()} does not allow this operation 
289 	 *    or {@link CollectionsExt.Modification#AddObj AddObj} 
290 	 *    is no allowed operation 
291 	 *    according to {@link #allowedModifications()}. 
292 	 *    In the latter case it does not matter, 
293 	 *    whether effectively it is tried to add an object 
294 	 *    which is the case only <code>this</code> 
295 	 *    does not already contain <code>obj</code>. 
296     	 */
297 	// overwrites method that throws UnsupportedOperationException
298     	public final boolean add(E obj) {
299     	    if (this.mods.contains(Modification.AddObj)) {
300 		// may throw UnsupportedOperationException
301     		return unrestricted().add(obj);
302     	    }
303 
304     	    throw new UnsupportedOperationException();
305     	}
306 
307     	/**
308     	 * @throws UnsupportedOperationException
309 	 *    if either {@link #unrestricted()} does not allow this operation 
310 	 *    or {@link CollectionsExt.Modification#RemoveObj RemoveObj} 
311 	 *    is no allowed operation 
312 	 *    according to {@link #allowedModifications()}. 
313 	 *    In the latter case it does not matter, 
314 	 *    whether effectively it is tried to remove an object 
315 	 *    which is the case only <code>this</code> 
316 	 *    contains <code>obj</code>. 
317       	 */
318     	public final boolean remove(Object obj) {
319     	    if (this.mods.contains(Modification.RemoveObj)) {
320 		// may throw UnsupportedOperationException
321     		return unrestricted().remove(obj);
322     	    }
323     	    throw new UnsupportedOperationException();
324     	}
325 
326 	// inherited from AbstractCollection: 
327 	// containsAll() 
328 
329     	/**
330     	 * @throws UnsupportedOperationException
331 	 *    if either {@link #unrestricted()} does not allow this operation 
332 	 *    or {@link CollectionsExt.Modification#RemoveObj RemoveObj} 
333 	 *    is no allowed operation 
334 	 *    according to {@link #allowedModifications()}. 
335 	 *    In the latter case it does not matter, 
336 	 *    whether effectively it is tried to clear <code>this</code> 
337 	 *    which is the case only if <code>this</code> is not empty already. 
338      	 */
339     	public final void clear() {
340     	    if (this.mods.contains(Modification.RemoveObj)) {
341 		// may throw UnsupportedOperationException
342     		unrestricted().clear();
343     	    }
344     	    throw new UnsupportedOperationException();
345     	}
346 
347 
348 	// Bulk Operations
349 
350 	// inherited from AbstractCollection: 
351 	// boolean containsAll(Collection<?> c)
352 
353     	/**
354     	 * @throws UnsupportedOperationException
355 	 *    if either {@link #unrestricted()} does not allow this operation 
356 	 *    or {@link CollectionsExt.Modification#AddObj AddObj} 
357 	 *    is no allowed operation 
358 	 *    according to {@link #allowedModifications()}. 
359 	 *    In the latter case it does not matter, 
360 	 *    whether effectively it is tried to add objects 
361 	 *    which is the case only if <code>coll</code> 
362 	 *    is not a subcollection of <code>this</code>. 
363     	 */
364 	// **** if modifications do not distinguish between add and addAll, 
365 	// this method need not be implemented: 
366 	// Extending AbstractSet, this method is supported 
367 	// iff so is add(E) 
368     	public final boolean addAll(Collection<? extends E> coll) {
369     	    if (this.mods.contains(Modification.AddObj)) {
370 		// may throw UnsupportedOperationException
371     		return unrestricted().addAll(coll);
372     	    }
373     	    throw new UnsupportedOperationException();
374     	}
375 
376     	/**
377     	 * @throws UnsupportedOperationException
378 	 *    if either {@link #unrestricted()} does not allow this operation 
379 	 *    or {@link CollectionsExt.Modification#RemoveObj RemoveObj} 
380 	 *    is no allowed operation 
381 	 *    according to {@link #allowedModifications()}. 
382 	 *    In the latter case it does not matter, 
383 	 *    whether effectively it is tried to remove objects 
384 	 *    which is the case only if <code>this</code> 
385 	 *    is not a subcollection of <code>coll</code>. 
386     	 */
387 	// **** if modifications do not distinguish 
388 	// between remove and removeAll and retainAll, 
389 	// this method need not be implemented: 
390 	// Extending AbstractSet, this method is supported 
391 	// iff so is remove(E) 
392     	public final boolean retainAll(Collection<?> coll) {
393     	    if (this.mods.contains(Modification.RemoveObj)) {
394 		// may throw UnsupportedOperationException
395     		return unrestricted().retainAll(coll);
396     	    }
397     	    throw new UnsupportedOperationException();
398     	}
399 
400     	/**
401     	 * @throws UnsupportedOperationException
402 	 *    if either {@link #unrestricted()} does not allow this operation 
403 	 *    or {@link CollectionsExt.Modification#RemoveObj RemoveObj} 
404 	 *    is no allowed operation 
405 	 *    according to {@link #allowedModifications()}. 
406 	 *    In the latter case it does not matter, 
407 	 *    whether effectively it is tried to remove objects 
408 	 *    which is the case only if <code>this</code> 
409 	 *    and <code>coll</code> are not disjoint. 
410      	 */
411 	// **** see retainAll(...) 
412     	public final boolean removeAll(Collection<?> cmp) {
413     	    if (this.mods.contains(Modification.RemoveObj)) {
414  		// may throw UnsupportedOperationException
415    		return unrestricted().removeAll(cmp);
416     	    }
417     	    throw new UnsupportedOperationException();
418     	}
419 
420     	/**
421     	 * @throws UnsupportedOperationException
422 	 *    if either {@link #unrestricted()} does not allow this operation 
423 	 *    or {@link CollectionsExt.Modification#RemoveObj RemoveObj} 
424 	 *    is no allowed operation 
425 	 *    according to {@link #allowedModifications()}. 
426 	 *    In the latter case it does not matter, 
427 	 *    whether effectively it is tried to remove objects 
428 	 *    which is the case only if <code>filter</code> 
429 	 *    accepts an element of <code>this</code>. 
430      	 */
431 	public final boolean removeIf(Predicate<? super E> filter) {
432     	    if (this.mods.contains(Modification.RemoveObj)) {
433  		// may throw UnsupportedOperationException
434    		return unrestricted().removeIf(filter);
435     	    }
436     	    throw new UnsupportedOperationException();
437 	}
438 
439     	/**
440     	 * Returns an iterator with method {@link Iterator#remove()} 
441 	 * which throws an {@link UnsupportedOperationException} 
442 	 * if either {@link #unrestricted()}'s iterator 
443 	 * does not allow this operation 
444 	 * or {@link CollectionsExt.Modification#RemoveObj RemoveObj} 
445 	 * is no allowed operation 
446 	 * according to {@link #allowedModifications()}. 
447     	 */
448     	public final Iterator<E> iterator() {
449 	    return new Iterator<E>() {
450 		private Iterator<E> wrapped = AbstractImmutableCollection.this
451 		    .unrestricted().iterator();
452 
453 		public boolean hasNext() {
454 		    return this.wrapped.hasNext();
455 		}
456 
457 		public E next() {
458 		    return this.wrapped.next();
459 		}
460 
461 		public void forEachRemaining(Consumer<? super E> action) {
462 		    this.wrapped.forEachRemaining(action);
463 		}
464 
465 		/**
466 		 * @throws UnsupportedOperationException
467 		 *    if either this iterator does not allow remove  
468 		 *    or 
469 		 *{@link CollectionsExt.Modification#RemoveObj RemoveObj} 
470 		 *    is no allowed operation 
471 		 *    according to {@link #allowedModifications()}. 
472 		 */
473 		public void remove() {
474 		    if (AbstractImmutableCollection.this.mods
475 			.contains(Modification.RemoveObj)) {
476 			// may throw UnsupportedOperationException
477 			this.wrapped.remove();
478 		    }
479 		    throw new UnsupportedOperationException();
480 		}
481 	    };
482     	}
483 
484 	/**
485 	 * Returns a string representation of this set, 
486 	 * including the allowed modifications 
487 	 * and the wrapped set. 
488 	 */
489 	public final String toString() {
490 	    StringBuilder res = new StringBuilder();
491 	    res.append("<Immutable modifications=\"");
492 	    res.append(this.mods);
493 	    res.append("\">");
494 	    res.append(unrestricted().toString());
495 	    res.append("</Immutable>");
496 	    return res.toString();
497 	}
498 
499 	// default void forEach(Consumer<? super T> action) 
500 	// is inherited from AbstractCollection 
501 
502     } // class AbstractImmutableCollection 
503 
504 
505     /**
506      * A collection which prevents being modified 
507      * by throwing an exception for the modifying methods. 
508      *
509      * @param <E>
510      *    the class of the elements of this collection. 
511      */
512     public static final class ImmutableCollection<E> 
513 	extends AbstractImmutableCollection<Collection<E>, E> 
514 	implements Collection<E> {
515 
516    	/* ---------------------------------------------------------------- *
517     	 * fields.                                                          *
518     	 * ---------------------------------------------------------------- */
519 
520 	/**
521 	 * The enclosed set containing the elements of this set. 
522 	 */
523 	private final Collection<E> coll;
524 
525     	/* ---------------------------------------------------------------- *
526     	 * constructors.                                                    *
527     	 * ---------------------------------------------------------------- */
528 
529     	/**
530     	 * Creates a new empty <code>ImmutableCollection</code> 
531     	 * which equals <code>coll</code> but cannot be modified 
532 	 * neither directly nor via its iterator. 
533 	 *
534 	 * @throws NullPointerException
535 	 *    if <code>coll==null</code>. 
536    	 */
537 	ImmutableCollection(Collection<E> coll) {
538 	    if (coll == null) {
539 		throw new NullPointerException(); // NOPMD
540 	    }
541 	    this.coll = coll;
542 	}
543 
544      	/* ---------------------------------------------------------------- *
545     	 * methods.                                                         *
546     	 * ---------------------------------------------------------------- */
547 
548 	public Collection<E> unrestricted() {
549 	    return this.coll;
550 	}
551 
552    } // class ImmutableCollection<E>
553 
554     /**
555      * A set which prevents being modified 
556      * by throwing an exception for the modifying methods. 
557      *
558      * @param <E>
559      *    the class of the elements of this set. 
560      */
561     public static final class ImmutableSet<E> 
562 	extends AbstractImmutableCollection<Set<E>, E> 
563 	implements Set<E> {
564 
565    	/* ---------------------------------------------------------------- *
566     	 * fields.                                                          *
567     	 * ---------------------------------------------------------------- */
568 
569 	/**
570 	 * The enclosed set containing the elements of this set. 
571 	 */
572 	private final Set<E> set;
573 
574    	/* ---------------------------------------------------------------- *
575     	 * constructors.                                                    *
576     	 * ---------------------------------------------------------------- */
577 
578 	ImmutableSet(Set<E> set) {
579 	    if (set == null) {
580 		throw new NullPointerException(); // NOPMD 
581 	    }
582 	    this.set = set;
583 	}
584 
585 	ImmutableSet(Set<Modification> mods, Set<E> set) {
586 	    super(mods);
587 	    if (set == null) {
588 		throw new NullPointerException(); // NOPMD 
589 	    }
590 	    this.set = set;
591 	}
592 
593       	/* ---------------------------------------------------------------- *
594     	 * methods.                                                         *
595     	 * ---------------------------------------------------------------- */
596 
597 	public Set<E> unrestricted() {
598 	    return this.set;
599 	}
600 
601     } // class ImmutableSet<E> 
602 
603     // **** modifications of views are allowed if allowed for original set. 
604     // changes in allowances are reflected in views. 
605     /**
606      * A sorted set which prevents being modified 
607      * by throwing an exception for the modifying methods. 
608      *
609      * @param <E>
610      *    the class of the elements of this list. 
611      */
612     public static final class ImmutableSortedSet<E> 
613 	extends AbstractImmutableCollection<SortedSet<E>, E> 
614 	implements SortedSet<E> {
615 
616    	/* ---------------------------------------------------------------- *
617     	 * fields.                                                          *
618     	 * ---------------------------------------------------------------- */
619 
620 	/**
621 	 * The enclosed sorted set containing the elements of this sorted set. 
622 	 */
623 	private final SortedSet<E> set;
624 
625     	/* ---------------------------------------------------------------- *
626     	 * constructors.                                                    *
627     	 * ---------------------------------------------------------------- */
628 
629 	ImmutableSortedSet(SortedSet<E> set) {
630 	    if (set == null) {
631 		throw new NullPointerException(); // NOPMD
632 	    }
633 	    this.set = set;
634 	}
635 
636 	ImmutableSortedSet(Set<Modification> mods, SortedSet<E> set) {
637 	    super(mods);
638 	    if (set == null) {
639 		throw new NullPointerException(); // NOPMD 
640 	    }
641 	    this.set = set;
642 	}
643 
644      	/* ---------------------------------------------------------------- *
645     	 * methods.                                                         *
646     	 * ---------------------------------------------------------------- */
647 
648 	public SortedSet<E> unrestricted() {
649 	    return this.set;
650 	}
651 
652 	public Comparator<? super E> comparator() {
653 	    return unrestricted().comparator();
654 	}
655 
656 	public E first() {
657 	    return unrestricted().first();
658 	}
659 
660 	public E last() {
661 	    return unrestricted().last();
662 	}
663 
664 	/**
665 	 * Returns a view of the portion of this set 
666 	 * whose elements are strictly less than <code>toElement</code>. 
667 	 * For information on backing see {@link #subSet(Object, Object)}. 
668 	 */
669 	public SortedSet<E> headSet(E toElement) {
670 	    SortedSet<E> res0 = unrestricted().headSet(toElement);
671 	    return new ImmutableSortedSet<E>(allowedModifications(), res0);
672 	}
673 
674 	/**
675 	 * Returns a view of the portion of this set 
676 	 * whose elements range from <code>fromElement</code>, 
677 	 * inclusive, to <code>toElement</code>, exclusive. 
678 	 * (If fromElement and toElement are equal, the returned set is empty.) 
679 	 * The returned set is backed by this set, 
680 	 * so changes in the returned set are reflected in this set, 
681 	 * and vice-versa. 
682 	 * The returned set supports all optional set operations 
683 	 * that this set supports. 
684 	 * In particular, changes of the allowed modifications 
685 	 * (returned by {@link #allowedModifications()}) 
686 	 * of the returned set are reflected in this set, and vice-versa. 
687 	 */
688 	public SortedSet<E> subSet(E fromElement, E toElement) {
689 	    SortedSet<E> res0 = unrestricted().subSet(fromElement, toElement);
690 	    return new ImmutableSortedSet<E>(allowedModifications(), res0);
691 	}
692 
693 	/**
694 	 * Returns a view of the portion of this set 
695 	 * whose elements are greater than or equal to <code>fromElement</code>.
696 	 * For information on backing see {@link #subSet(Object, Object)}. 
697 	 */
698 	public SortedSet<E> tailSet(E fromElement) {
699 	    SortedSet<E> res0 = unrestricted().tailSet(fromElement);
700 	    return new ImmutableSortedSet<E>(allowedModifications(), res0);
701 	}
702     } // class ImmutableSortedSet<E> 
703 
704     /**
705      * A list which prevents being modified 
706      * by throwing an exception for the modifying methods. 
707      *
708      * @param <E>
709      *    the class of the elements of this list. 
710      */
711     public static final class ImmutableList<E> 
712 	extends AbstractImmutableCollection<List<E>, E> 
713 	implements List<E> {
714 
715    	/* ---------------------------------------------------------------- *
716     	 * fields.                                                          *
717     	 * ---------------------------------------------------------------- */
718 
719 	/**
720 	 * The enclosed list containing the elements of this list. 
721 	 */
722 	private final List<E> list;
723 
724     	/* ---------------------------------------------------------------- *
725     	 * constructors.                                                    *
726     	 * ---------------------------------------------------------------- */
727 
728 	ImmutableList(List<E> list) {
729 	    if (list == null) {
730 		throw new NullPointerException(); // NOPMD
731 	    }
732 	    this.list = list;
733 	}
734 
735 	ImmutableList(Set<Modification> mods, List<E> list) {
736 	    super(mods);
737 	    if (list == null) {
738 		throw new NullPointerException(); // NOPMD
739 	    }
740 	    this.list = list;
741 	}
742 
743     	/* ---------------------------------------------------------------- *
744     	 * methods.                                                         *
745     	 * ---------------------------------------------------------------- */
746 
747 	public List<E> unrestricted() {
748 	    return this.list;
749 	}
750 
751     	/**
752     	 * @throws UnsupportedOperationException
753 	 *    if either {@link #unrestricted()} does not allow this operation 
754 	 *    or {@link CollectionsExt.Modification#AddObj AddObj} 
755 	 *    is no allowed operation 
756 	 *    according to {@link #allowedModifications()}. 
757     	 */
758 	public void add(int index, E obj) {
759     	    if (!allowedModifications().contains(Modification.AddObj)) {
760 		throw new UnsupportedOperationException();
761     	    }
762 	    // may throw UnsupportedOperationException
763 	    unrestricted().add(index, obj);
764  	}
765 
766     	/**
767     	 * @throws UnsupportedOperationException
768 	 *    if either {@link #unrestricted()} does not allow this operation 
769 	 *    or {@link CollectionsExt.Modification#AddObj AddObj} 
770 	 *    is no allowed operation 
771 	 *    according to {@link #allowedModifications()}. 
772  	 *    In the latter case it does not matter, 
773 	 *    whether effectively it is tried to add objects 
774 	 *    which is the case only <code>coll</code> is not empty. 
775    	 */
776 	public boolean addAll(int index, Collection<? extends E> coll) {
777     	    if (allowedModifications().contains(Modification.AddObj)) {
778 		// may throw UnsupportedOperationException
779     		return unrestricted().addAll(index, coll);
780     	    }
781     	    throw new UnsupportedOperationException();
782 	}
783 
784 	public E get(int index) {
785 	    return unrestricted().get(index);
786 	}
787 
788 	// must be implemented because contract differs from that of Collection 
789 	public int hashCode() {
790 	    return unrestricted().hashCode();
791 	}
792 
793 	// must be implemented because hashCode() changed also  
794 	public boolean equals(Object obj) {
795 	    return unrestricted().equals(obj);
796 	}
797 
798 	public int indexOf(Object obj) {
799 	    return unrestricted().indexOf(obj);
800 	}
801 
802 	public int lastIndexOf(Object obj) {
803 	    return unrestricted().lastIndexOf(obj);
804 	}
805 
806 	public ListIterator<E> listIterator() {
807 	    return listIterator(0);
808 	}
809 
810 	public ListIterator<E> 	listIterator(int index) {
811 	    return new ListIterator<E>() {
812 
813 		private ListIterator<E> wrapped = ImmutableList.this
814 		    .unrestricted().listIterator();
815 
816 		public boolean hasNext() {
817 		    return this.wrapped.hasNext();
818 		}
819 		public E next() {
820 		    return this.wrapped.next();
821 		}
822 		public int nextIndex() {
823 		    return this.wrapped.nextIndex();
824 		}
825 		public boolean hasPrevious() {
826 		    return this.wrapped.hasPrevious();
827 		}
828 		public E previous() {
829 		    return this.wrapped.previous();
830 		}
831 		public int previousIndex() {
832 		    return this.wrapped.previousIndex();
833 		}
834 
835 		public void forEachRemaining(Consumer<? super E> action) {
836 		    this.wrapped.forEachRemaining(action);
837 		}
838 
839 		/**
840 		 * @throws UnsupportedOperationException
841 		 *    if either this iterator does not allow remove  or 
842 		 *    {@link CollectionsExt.Modification#RemoveObj RemoveObj}
843 		 *    is no allowed operation 
844 		 *    according to {@link #allowedModifications()}. 
845 		 */
846 		public void remove() {
847 		    if (ImmutableList.this.allowedModifications()
848 			.contains(Modification.RemoveObj)) {
849 			// may throw UnsupportedOperationException
850 			this.wrapped.remove();
851 		    }
852 		    throw new UnsupportedOperationException();
853 		}
854 
855 		/**
856 		 * @throws UnsupportedOperationException
857 		 *    if either this iterator does not allow remove  
858 		 *    or {@link CollectionsExt.Modification#AddObj AddObj} 
859 		 *    is no allowed operation 
860 		 *    according to {@link #allowedModifications()}. 
861 		 */
862 		public void add(E element) {
863 		    if (ImmutableList.this.allowedModifications()
864 			.contains(Modification.AddObj)) {
865 			// may throw UnsupportedOperationException
866 			this.wrapped.add(element);
867 		    }
868 		    throw new UnsupportedOperationException();
869 		}
870 
871 		/**
872 		 * @throws UnsupportedOperationException
873 		 *    if either this iterator does not allow remove  
874 		 *    or {@link CollectionsExt.Modification#SetObj SetObj} 
875 		 *    is no allowed operation 
876 		 *    according to {@link #allowedModifications()}. 
877 		 *    In the latter case it does not matter, 
878 		 *    whether effectively it is tried to set an object 
879 		 *    which is the case only if <code>element</code> 
880 		 *    is not yet on the place this iterator points to. 
881  		 */
882 		public void set(E element) {
883 		    if (ImmutableList.this.allowedModifications()
884 			.contains(Modification.SetObj)) {
885 			// may throw UnsupportedOperationException
886 			this.wrapped.add(element);
887 		    }
888 		    throw new UnsupportedOperationException();
889 		}
890 	    };
891 	} // listIterator 
892 
893     	/**
894     	 * @throws UnsupportedOperationException
895 	 *    if either {@link #unrestricted()} does not allow this operation 
896 	 *    or {@link CollectionsExt.Modification#RemoveObj RemoveObj} 
897 	 *    is no allowed operation 
898 	 *    according to {@link #allowedModifications()}. 
899     	 */
900 	public E remove(int index) {
901    	    if (allowedModifications().contains(Modification.RemoveObj)) {
902 		// may throw UnsupportedOperationException
903 		return unrestricted().remove(index);
904     	    }
905 	    throw new UnsupportedOperationException();
906 	}
907 
908     	/**
909     	 * @throws UnsupportedOperationException
910 	 *    if either {@link #unrestricted()} does not allow this operation 
911 	 *    or {@link CollectionsExt.Modification#SetObj SetObj} 
912 	 *    is no allowed operation 
913 	 *    according to {@link #allowedModifications()}. 
914 	 *    In the latter case it does not matter, 
915 	 *    whether effectively it is tried to set an object 
916 	 *    which is the case only if <code>element</code> 
917 	 *    is not at place <code>index</code> in <code>this</code>. 
918      	 */
919 	public E set(int index, E element) {
920    	    if (allowedModifications().contains(Modification.SetObj)) {
921 		// may throw UnsupportedOperationException
922 		return unrestricted().set(index, element);
923     	    }
924 	    throw new UnsupportedOperationException();
925 	}
926 
927     	/**
928     	 * @throws UnsupportedOperationException
929 	 *    if either {@link #unrestricted()} does not allow this operation 
930 	 *    or {@link CollectionsExt.Modification#SetObj SetObj} 
931 	 *    is no allowed operation 
932 	 *    according to {@link #allowedModifications()}. 
933 	 *    In the latter case it does not matter, 
934 	 *    whether effectively it is tried to replace an object 
935 	 *    which is the case only if <code>operator</code> 
936 	 *    really changes an object. 
937      	 */
938 	public void replaceAll(UnaryOperator<E> operator) {
939    	    if (!allowedModifications().contains(Modification.SetObj)) {
940 		throw new UnsupportedOperationException();
941   	    }
942 	    // may throw UnsupportedOperationException
943 	    unrestricted().replaceAll(operator);
944   	}
945 
946     	/**
947     	 * @throws UnsupportedOperationException
948 	 *    if either {@link #unrestricted()} does not allow this operation 
949 	 *    or {@link CollectionsExt.Modification#SetObj SetObj} 
950 	 *    is no allowed operation 
951 	 *    according to {@link #allowedModifications()}. 
952 	 *    In the latter case it does not matter, 
953 	 *    whether effectively it is tried to replace an object 
954 	 *    which is the case only if <code>this</code> 
955 	 *    is not completely sorted according to <code>cmp</code>. 
956 	 *    This definition is in conjunction with the requirement, 
957 	 *    of {@link List#sort(Comparator)} 
958 	 *    that this exception is thrown iff the list iterator 
959 	 *    does not permit the {@link ListIterator#set(Object)} method. 
960      	 */
961 	public void sort(Comparator<? super E> cmp) {
962    	    if (!allowedModifications().contains(Modification.SetObj)) {
963 		throw new UnsupportedOperationException();
964     	    }
965 	    // may throw UnsupportedOperationException
966 	    unrestricted().sort(cmp);
967 	}
968 
969 	public List<E> subList(int fromIndex, int toIndex) {
970 	    List<E> res0 = unrestricted().subList(fromIndex, toIndex);
971 	    return new ImmutableList<E>(allowedModifications(), res0);
972 	}
973 
974     } // class ImmutableList
975 
976     /**
977      * An interator which prevents modification on the underlying list, 
978      * by throwing an exception for the modifying methods. 
979      * This is used in conjunction 
980      * with {@link CollectionsExt.ImmutableCyclicList}. 
981      *
982      * @param <E>
983      *    the class of the elements to iterate over. 
984      */
985     public static final class NonModifyingCyclicIterator<E> 
986 	implements CyclicIterator<E> {
987 
988 	private final CyclicIterator<E> wrapped;
989 
990 	NonModifyingCyclicIterator(CyclicIterator<E> wrapped) {
991 	    this.wrapped = wrapped;
992 	}
993 
994 	public int getFirstIndex() {
995 	    return this.wrapped.getFirstIndex();
996 	}
997 	public int getIndex() {
998 	    return this.wrapped.getIndex();
999 	}
1000 	public CyclicList<E> getCyclicList() {
1001 	    return this.wrapped.getCyclicList();
1002 	}
1003 	public boolean hasNext() {
1004 	    return this.wrapped.hasNext();
1005 	}
1006 	public E next() {
1007 	    return this.wrapped.next();
1008 	}
1009 
1010 	public boolean hasPrev() {
1011 	    return this.wrapped.hasPrev();
1012 	}
1013 
1014 	public E previous() {
1015 	    return this.wrapped.previous();
1016 	}
1017 
1018 	public int getNextIndexOf(E obj) {
1019 	    return this.wrapped.getNextIndexOf(obj);
1020 	}
1021 
1022 	public void setIndex(int index) {
1023 	    this.wrapped.setIndex(index);
1024 	}
1025 
1026 	public void add(E obj) {
1027 	    throw new UnsupportedOperationException();
1028 	}
1029 
1030 	public void addAll(List<? extends E> list) {
1031 	    throw new UnsupportedOperationException();
1032 	}
1033 
1034 	public void set(E obj) {
1035 	    throw new UnsupportedOperationException();
1036 	}
1037 	public void remove() {
1038 	    throw new UnsupportedOperationException();
1039 	}
1040 
1041 	public void refresh() {
1042 	    throw new UnsupportedOperationException();
1043 	}
1044 
1045 	public boolean retEquals(CyclicIterator<?> other) {
1046 	    throw new NotYetImplementedException();
1047 	}
1048 
1049 	@edu.umd.cs.findbugs.annotations.SuppressWarnings
1050 	    (value = "EQ_UNUSUAL", 
1051 	     justification = "special kind of exception")
1052 	public boolean equals(Object other) {
1053 	    throw new NotYetImplementedException();
1054 	}
1055 	public int hashCode() {
1056 	    throw new NotYetImplementedException();
1057 	}
1058 	public double dist(CyclicIterator<E> other) {
1059 	    throw new NotYetImplementedException();
1060 	}
1061 
1062     } // NonModifyingCyclicIterator 
1063 
1064     /**
1065      * Represents an immutable cyclic list 
1066      * by throwing an exception 
1067      * when invoking a method which modifies this list. 
1068      *
1069      * @param <E>
1070      *    the class of the elements of this list. 
1071      */
1072     public static final class ImmutableCyclicList<E> implements CyclicList<E> {
1073 
1074 	private final CyclicList<E> wrapped;
1075 
1076 	ImmutableCyclicList(CyclicList<E> wrapped) {
1077 	    this.wrapped = wrapped;
1078 	}
1079 
1080 	// ***** to be removed later. 
1081 	public int shiftIndex(int index) {
1082 	    throw new NotYetImplementedException();
1083 	}
1084 	public int size() {
1085 	    return this.wrapped.size();
1086 	}
1087 
1088 	// based on size() 
1089 	public boolean isEmpty() {
1090 	    return this.wrapped.isEmpty();
1091 	}
1092 
1093 	public CyclicList<E> getInverse() {
1094 	    throw new NotYetImplementedException();
1095 	}
1096 
1097 	// based on getIndexOf(...)
1098 	public boolean contains(Object obj) {
1099 	    return this.wrapped.contains(obj);
1100 	}
1101 
1102 	// based on contains(Object) 
1103 	public boolean containsAll(Collection<?> coll) {
1104 	    throw new NotYetImplementedException();
1105 	}
1106 
1107 	public Iterator<E> iterator() {
1108 	    throw new NotYetImplementedException();
1109 	}
1110 
1111 	// public Iterator<E> iterator(int index) {
1112 	//     throw new NotYetImplementedException();
1113 	// }
1114 
1115 	public CyclicIterator<E> cyclicIterator(int index) {
1116 	    CyclicIterator<E> tbWrapped = this.wrapped.cyclicIterator(index);
1117 	    return new NonModifyingCyclicIterator<E>(tbWrapped);
1118 	}
1119 
1120 	public Object[] toArray(int index) {
1121 	    throw new NotYetImplementedException();
1122 	}
1123 	public <E> E[] toArray(int index, E[] array) {
1124 	    throw new NotYetImplementedException();
1125 	}
1126 	public Object[] toArray() {
1127 	    throw new NotYetImplementedException();
1128 	}
1129 	public <E> E[] toArray(E[] ret) {
1130 	    throw new NotYetImplementedException();
1131 	}
1132 	public List<E> asList(int index) {
1133 	    throw new NotYetImplementedException();
1134 	}
1135 	public List<E> asList() {
1136 	    return Collections.unmodifiableList(this.wrapped.asList());
1137 	}
1138 	public CyclicList<E> cycle(int num) {
1139 	    throw new NotYetImplementedException();
1140 	}
1141 
1142 	public void clear() {
1143     	    throw new UnsupportedOperationException();
1144 	}
1145 
1146 	public boolean equals(Object obj) {
1147 	    return this.wrapped.equals(obj);
1148 	}
1149 	public boolean equalsCyclic(Object obj) {
1150 	    return this.wrapped.equalsCyclic(obj);
1151 	}
1152 	public int hashCode() {
1153 	    return this.wrapped.hashCode();
1154 	}
1155 	public int hashCodeCyclic() {
1156 	    return this.wrapped.hashCodeCyclic();
1157 	}
1158 	public E get(int index) {
1159 	    return this.wrapped.get(index);
1160 	}
1161 	public E set(int index, E element) {
1162     	    throw new UnsupportedOperationException();
1163 	}
1164 	public void replace(int index, Iterator<E> iter) {
1165    	    throw new UnsupportedOperationException();
1166 	}
1167 	public void replace(int index, List<E> list) {
1168    	    throw new UnsupportedOperationException();
1169 	}
1170 	public boolean add(E element) {
1171 	    throw new UnsupportedOperationException();
1172 	}
1173 	public void add(int index, E element) {
1174    	    throw new UnsupportedOperationException();
1175 	}
1176 	public void addAll(int index, Iterator<E> iter) {
1177    	    throw new UnsupportedOperationException();
1178 	}
1179 	public void addAll(int index, List<? extends E> list) {
1180    	    throw new UnsupportedOperationException();
1181 	}
1182 	public boolean addAll(Collection<? extends E> coll) {
1183 	    throw new UnsupportedOperationException(); // for cyclic lists 
1184 	}
1185 	public E remove(int index) throws EmptyCyclicListException {
1186    	    throw new UnsupportedOperationException();
1187 	}
1188 	public boolean remove(Object obj) {
1189    	    throw new UnsupportedOperationException();
1190 	}
1191 	public boolean removeAll(Collection<?> coll) {
1192    	    throw new UnsupportedOperationException();
1193 	}
1194 	public boolean retainAll(Collection<?> coll) {
1195    	    throw new UnsupportedOperationException();
1196 	}
1197 	public int getIndexOf(int idx, Object obj) {
1198 	    throw new NotYetImplementedException();
1199 	}
1200 	public CyclicList<E> getCopy(int len) {
1201 	    throw new NotYetImplementedException();
1202 	}
1203 
1204     } // class ImmutableCyclicList 
1205 
1206     /**
1207      * An immutable implementation of the multiplicity interface. 
1208      */
1209     private static class ImmutableMultiplicity 
1210 	implements MultiSet.Multiplicity {
1211 
1212 	private final MultiSet.Multiplicity wrapped;
1213 	private final Set<Modification> mod;
1214 
1215 	ImmutableMultiplicity(MultiSet.Multiplicity wrapped, 
1216 			      Set<Modification> mod) {
1217 	    this.wrapped = wrapped;
1218 	    this.mod = mod;
1219 	}
1220 
1221 	private Set<Modification> allowedModifications() {
1222 	    return this.mod;
1223 	}
1224 
1225 	public int set(int mult) {
1226 	    int multOrg = this.wrapped.get();
1227 
1228 	    // **** may cause problems with over/underflow 
1229 	    switch ((int) Math.signum(mult - multOrg)) {
1230 	    case -1:
1231 		assert mult < multOrg;
1232 		if (allowedModifications()
1233 		    .contains(Modification.RemoveObj)) {
1234 		    // may throw UnsupportedOperationException
1235 		    return this.wrapped.set(mult);
1236 		}
1237 		break;
1238 	    case +1:
1239 		assert mult > multOrg;
1240 		if (allowedModifications()
1241 		    .contains(Modification.AddObj)) {
1242 		    // may throw UnsupportedOperationException
1243 		    return this.wrapped.set(mult);
1244 		}
1245 		break;
1246 	    case 0:
1247 		assert mult == multOrg;
1248 		// this does not modify the multiplicity 
1249 		// but just returns the current value. 
1250 		// could also return multOrg 
1251 		return this.wrapped.set(mult);
1252 	    default:
1253 		throw new IllegalStateException("****");
1254 	    }
1255 	    throw new UnsupportedOperationException();
1256 	}
1257 
1258 	public int add(int mult) {
1259 	    switch ((int) Math.signum(mult)) {
1260 	    case -1:
1261 		assert mult < 0;
1262 		if (allowedModifications()
1263 		    .contains(Modification.RemoveObj)) {
1264 		    // may throw UnsupportedOperationException
1265 		    return this.wrapped.add(mult);
1266 		}
1267 		break;
1268 	    case +1:
1269 		assert mult > 0;
1270 		if (allowedModifications()
1271 		    .contains(Modification.AddObj)) {
1272 		    // may throw UnsupportedOperationException
1273 		    return this.wrapped.add(mult);
1274 		}
1275 		break;
1276 	    case 0:
1277 		assert mult == 0;
1278 		// this does not modify the multiplicity 
1279 		// but just returns the current value. 
1280 		return this.wrapped.add(mult);
1281 	    default:
1282 		throw new IllegalStateException("****");
1283 	    }
1284 	    throw new UnsupportedOperationException();
1285 	}
1286 
1287 	public int get() {
1288 	    return this.wrapped.get();
1289 	}
1290 
1291 	public int compareTo(MultiSet.Multiplicity mult) {
1292 	    return this.wrapped.compareTo(mult);
1293 	}
1294 
1295 	/**
1296 	 * Returns <code>true</code> if and only if 
1297 	 * <code>obj</code> is also an instance of <code>Multiplicity</code> 
1298 	 * and if the wrapped multiplicities coincide. 
1299 	 *
1300 	 * @param obj 
1301 	 *    an <code>Object</code> value 
1302 	 *    which may well be <code>null</code>. 
1303 	 * @return 
1304 	 *    a <code>boolean</code> value which indicates 
1305 	 *    whether <code>obj</code> is also an instance 
1306 	 *    of <code>Multiplicity</code> 
1307 	 *    and whether the wrapped multiplicity coincides with this one. 
1308 	 * @see #compareTo
1309 	 */
1310 	public boolean equals(Object obj) {
1311 	    return this.wrapped.equals(obj);
1312 	}
1313 
1314 	// api-docs provided by javadoc. 
1315 	public int hashCode() {
1316 	    return this.wrapped.hashCode();
1317 	}
1318 
1319 
1320     } // class ImmutableMultiplicity 
1321 
1322     /**
1323      * A MultiSet which prevents being modified 
1324      * by throwing an exception for the modifying methods. 
1325      *
1326      * @param <C>
1327      *    the class extending {@link MultiSet} with elements in E. 
1328      * @param <E>
1329      *    the class of the elements of this collection. 
1330      */
1331     abstract static class AbstractImmutableMultiSet<C extends MultiSet<E>, E> 
1332 	implements MultiSet<E> {
1333 
1334     	private static final long serialVersionUID = -2479143000061671589L;
1335 
1336     	/* ---------------------------------------------------------------- *
1337     	 * fields.                                                          *
1338     	 * ---------------------------------------------------------------- */
1339 
1340 	// ***** same as for AbstractImmutableCollection 
1341 	/**
1342 	 * The set of allowed modifications. 
1343 	 */
1344     	private final Set<Modification> mods;
1345 
1346     	/* ---------------------------------------------------------------- *
1347     	 * constructors.                                                    *
1348     	 * ---------------------------------------------------------------- */
1349 
1350 	// ***** same as for AbstractCollection 
1351 	private AbstractImmutableMultiSet() {
1352    	    this(EnumSet.noneOf(Modification.class));
1353 	}
1354 
1355 	// ***** same as for AbstractCollection 
1356 	AbstractImmutableMultiSet(Set<Modification> mods) {
1357    	    this.mods = mods;
1358 	}
1359 
1360     	/* ---------------------------------------------------------------- *
1361     	 * methods.                                                         *
1362     	 * ---------------------------------------------------------------- */
1363 
1364     	public final Set<Modification> allowedModifications() {
1365     	    return this.mods;
1366     	}
1367 
1368 	/**
1369 	 * Returns the underlying multiset without the restrictions 
1370 	 * imposed by this {@link CollectionsExt.ImmutableCollection}. 
1371 	 * Note that the result 
1372 	 * may still throw {@link UnsupportedOperationException}s 
1373 	 * depending on the implementation. 
1374 	 */
1375 	public abstract C unrestricted();
1376 
1377 	// query methods 
1378 
1379 	public int size() {
1380 	    return unrestricted().size();
1381 	}
1382 
1383 	public int sizeWithMult() {
1384 	    return unrestricted().sizeWithMult();
1385 	}
1386 
1387 	public boolean isEmpty() {
1388 	    return unrestricted().isEmpty();
1389 	}
1390 
1391 	public Object getObjWithMaxMult() {
1392 	    return unrestricted().getObjWithMaxMult();
1393 	}
1394 
1395 	public int getMaxMult() {
1396 	    return unrestricted().getMaxMult();
1397 	}
1398 
1399 	public int getMultiplicity(Object obj) {
1400 	    return unrestricted().getMultiplicity(obj);
1401 	}
1402 
1403 	public boolean contains(Object obj) {
1404 	    return unrestricted().contains(obj);
1405 	}
1406 
1407 	public Object[] toArray() {
1408 	    return unrestricted().toArray();
1409 	}
1410 
1411 	public E[] toArray(E[] arr) {
1412 	    return unrestricted().toArray(arr);
1413 	}
1414 
1415 	// What follows are query methods the return value of which 
1416 	// is required to prevent modifications. 
1417 
1418 	public Multiplicity getMultiplicityObj(Object obj) {
1419 	    Multiplicity res0 = this.unrestricted().getMultiplicityObj(obj);
1420 	    return new ImmutableMultiplicity(res0, this.allowedModifications());
1421 	}
1422 
1423 	public MultiSetIterator<E> iterator() {
1424 	    return new MultiSetIterator<E>() {
1425 		private MultiSetIterator<E> wrapped = 
1426 		    AbstractImmutableMultiSet.this.unrestricted().iterator();
1427 
1428 		public boolean hasNext() {
1429 		    return this.wrapped.hasNext();
1430 		}
1431 
1432 		public E next() {
1433 		    return this.wrapped.next();
1434 		}
1435 
1436 		public void forEachRemaining(Consumer<? super E> action) {
1437 		    this.wrapped.forEachRemaining(action);
1438 		}
1439 
1440 		public void remove() {
1441 		    if (AbstractImmutableMultiSet.this.mods
1442 			.contains(Modification.RemoveObj)) {
1443 			// may throw UnsupportedOperationException
1444 			this.wrapped.remove();
1445 		    }
1446 		    throw new UnsupportedOperationException();
1447 		}
1448 
1449 		public int getMult() {
1450 		    return this.wrapped.getMult();
1451 		}
1452 
1453 		public MultiSet.Multiplicity getMultObj() {
1454 		    return this.wrapped.getMultObj();
1455 		}
1456 
1457 		// this is always the same as for mutable multi-sets. 
1458 		// I think, one has to decide: 
1459 		// There is a single method exposing Multiplicities: 
1460 		// MultiSet.getMultiplicityObj(Object). 
1461 		// If this is ok, then we may replace in MultiSetIterator 
1462 		// setMult and removeMult by getMultObj.set() 
1463 		// and getMultObj.remove(int) 
1464 		//
1465 		// If we agree that Multiplicities are not public, 
1466 		// then we must turn 
1467 		// MultiSet.getMultiplicityObj(Object) protected
1468 		// but we must define iterator with method 
1469 		// protected getMultObj and implement 
1470 		// setMult and removeMult in terms of getMultObj. 
1471 		// Moreover we need a method iteratorInternal 
1472 		// which exposes getMultObj to the immutable iterator 
1473 		// and make sure that setMult and removeMult 
1474 		// are implemented as in base class. 
1475 
1476 		// Here getMultObj() returns an immutable Multiplicity 
1477 		public int setMult(int mult) {
1478 		    // **** copy from MultiSetIteratorImpl 
1479 		    // can be avoided using default final in interface 
1480 		    // may throw IllegalStateException 
1481 		    Multiplicity last = getMultObj();
1482 		    assert last != null;
1483 		    if (mult == 0) {
1484 			int res = last.get();
1485 			// may throw UnsupportedOperationException
1486 			remove();
1487 			return res;
1488 		    }
1489 		    // may throw IllegalArgumentException
1490 		    // may throw UnsupportedOperationException
1491 		    return last.set(mult);
1492 		    //throw new NotYetImplementedException();
1493 		}
1494 
1495 		// Here getMultObj() returns an immutable Multiplicity 
1496 		public int removeMult(int mult) {
1497 		    // **** copy from MultiSetIteratorImpl
1498 		    // may throw IllegalStateException 
1499 		    Multiplicity last = getMultObj();
1500 		    assert last != null;
1501 		    // return value is old multiplicity 
1502 		    int oldMult = last.get();
1503 		    if (mult == oldMult) {
1504 			remove();
1505 			return oldMult;
1506 		    }
1507 
1508 		    // may throw an IllegalArgumentException 
1509 		    // may throw UnsupportedOperationException
1510 		    last.add(-mult);
1511 		    return oldMult;
1512 		}
1513 	    };
1514 	}
1515 
1516 	public int addWithMult(E obj) {
1517     	    if (this.mods.contains(Modification.AddObj)) {
1518 		// may throw UnsupportedOperationException
1519     		return unrestricted().addWithMult(obj);
1520     	    }
1521     	    throw new UnsupportedOperationException();
1522 	}
1523 
1524 	public int addWithMult(E obj, int addMult) {
1525     	    if (this.mods.contains(Modification.AddObj)) {
1526 		// may throw UnsupportedOperationException
1527     		return unrestricted().addWithMult(obj, addMult);
1528     	    }
1529     	    throw new UnsupportedOperationException();
1530 	}
1531 
1532 	public boolean add(E obj) {
1533     	    if (this.mods.contains(Modification.AddObj)) {
1534 		// may throw UnsupportedOperationException
1535     		return unrestricted().add(obj);
1536     	    }
1537     	    throw new UnsupportedOperationException();
1538 	}
1539 
1540 	public int removeWithMult(Object obj) {
1541     	    if (this.mods.contains(Modification.RemoveObj)) {
1542 		// may throw UnsupportedOperationException
1543     		return unrestricted().removeWithMult(obj);
1544     	    }
1545     	    throw new UnsupportedOperationException();
1546 	}
1547 
1548 	public int removeWithMult(Object obj, int removeMult) {
1549     	    if (this.mods.contains(Modification.RemoveObj)) {
1550 		// may throw UnsupportedOperationException
1551     		return unrestricted().removeWithMult(obj, removeMult);
1552     	    }
1553     	    throw new UnsupportedOperationException();
1554 	}
1555 
1556 	public boolean remove(Object obj) {
1557     	    if (this.mods.contains(Modification.RemoveObj)) {
1558 		// may throw UnsupportedOperationException
1559     		return unrestricted().remove(obj);
1560     	    }
1561     	    throw new UnsupportedOperationException();
1562 	}
1563 
1564 	public int setMultiplicity(E obj, int newMult) {
1565 	    throw new NotYetImplementedException();
1566 	}
1567 
1568 	public boolean containsAll(Collection<?> coll) {
1569 	    return unrestricted().containsAll(coll);
1570 	}
1571 
1572 	public boolean addAll(MultiSet<? extends E> mvs) {
1573     	    if (this.mods.contains(Modification.AddObj)) {
1574 		// may throw UnsupportedOperationException
1575     		return unrestricted().addAll(mvs);
1576     	    }
1577     	    throw new UnsupportedOperationException();
1578 	}
1579 
1580 	public boolean addAll(Set<? extends E> set) {
1581     	    if (this.mods.contains(Modification.AddObj)) {
1582 		// may throw UnsupportedOperationException
1583     		return unrestricted().addAll(set);
1584     	    }
1585     	    throw new UnsupportedOperationException();
1586 	}
1587 
1588 	public boolean removeAll(Collection<?> coll) {
1589     	    if (this.mods.contains(Modification.RemoveObj)) {
1590 		// may throw UnsupportedOperationException
1591     		return unrestricted().removeAll(coll);
1592     	    }
1593     	    throw new UnsupportedOperationException();
1594 	}
1595 
1596 	public boolean retainAll(Collection<?> coll) {
1597     	    if (this.mods.contains(Modification.RemoveObj)) {
1598 		// may throw UnsupportedOperationException
1599     		return unrestricted().retainAll(coll);
1600     	    }
1601     	    throw new UnsupportedOperationException();
1602 	}
1603 
1604 	public void clear() {
1605     	    if (!this.mods.contains(Modification.RemoveObj)) {
1606 		throw new UnsupportedOperationException();
1607   	    }
1608 	    // may throw UnsupportedOperationException
1609 	    unrestricted().clear();
1610   	}
1611 
1612 	public Set<E> getSet() {
1613 	    return new ImmutableSet<E>(allowedModifications(),
1614 				       unrestricted().getSet());
1615 	}
1616 
1617 	public Map<E, Multiplicity> getMap() {
1618 	    throw new NotYetImplementedException();
1619 	}
1620 
1621 	public Set<Map.Entry<E, Multiplicity>> getSetWithMults() {
1622 	    return new ImmutableSet<Map.Entry<E, Multiplicity>>
1623 		(allowedModifications(), unrestricted().getSetWithMults());
1624 	}
1625 
1626 	// **** as in AbstractImmutableCollection
1627 	public String toString() {
1628 	    StringBuilder res = new StringBuilder();
1629 	    res.append("<Immutable modifications=\">");
1630 	    res.append(this.mods);
1631 	    res.append("\">");
1632 	    res.append(unrestricted().toString());
1633 	    res.append("</Immutable>");
1634 	    return res.toString();
1635 	}
1636 
1637 	public boolean equals(Object obj) {
1638 	    return unrestricted().equals(obj);
1639 	}
1640 
1641 	public int hashCode() {
1642 	    return unrestricted().hashCode();
1643 	}
1644 
1645     } // class AbstractImmutableMultiSet 
1646 
1647     /**
1648      * A multi-set which prevents being modified 
1649      * by throwing an exception for the modifying methods. 
1650      *
1651      * @param <E>
1652      *    the class of the elements of this list. 
1653      */
1654     static class ImmutableMultiSet<E> 
1655 	extends AbstractImmutableMultiSet<MultiSet<E>, E> 
1656 	implements MultiSet<E> {
1657 
1658    	/* ---------------------------------------------------------------- *
1659     	 * fields.                                                          *
1660     	 * ---------------------------------------------------------------- */
1661 
1662 	/**
1663 	 * The enclosed multi-set containing the elements of this multi-set. 
1664 	 */
1665 	private final MultiSet<E> mSet;
1666 
1667     	/* ---------------------------------------------------------------- *
1668     	 * constructors.                                                    *
1669     	 * ---------------------------------------------------------------- */
1670 
1671     	/**
1672     	 * Creates a new empty <code>ImmutableMultiSet</code> 
1673     	 * which equals <code>mSet</code> but cannot be modified 
1674 	 * neither directly nor via its iterator. 
1675 	 *y
1676 	 * @throws NullPointerException
1677 	 *    if <code>coll==null</code>. 
1678    	 */
1679 	ImmutableMultiSet(MultiSet<E> mSet) {
1680 	    if (mSet == null) {
1681 		throw new NullPointerException(); // NOPMD
1682 	    }
1683 	    this.mSet = mSet;
1684 	}
1685 
1686     	/* ---------------------------------------------------------------- *
1687     	 * methods.                                                         *
1688     	 * ---------------------------------------------------------------- */
1689 
1690 	public MultiSet<E> unrestricted() {
1691 	    return this.mSet;
1692 	}
1693     } // class ImmutableMultiSet
1694 
1695     /**
1696      * A sorted multi-set which prevents being modified 
1697      * by throwing an exception for the modifying methods. 
1698      *
1699      * @param <E>
1700      *    the class of the elements of this list. 
1701      */
1702     static class ImmutableSortedMultiSet<E> 
1703 	extends AbstractImmutableMultiSet<SortedMultiSet<E>, E> 
1704 	implements SortedMultiSet<E> {
1705 
1706    	/* ---------------------------------------------------------------- *
1707     	 * fields.                                                          *
1708     	 * ---------------------------------------------------------------- */
1709 
1710 	private final SortedMultiSet<E> mSet;
1711 
1712     	/* ---------------------------------------------------------------- *
1713     	 * constructors.                                                    *
1714     	 * ---------------------------------------------------------------- */
1715 
1716 	/**
1717     	 * Creates a new empty <code>ImmutableSortedMultiSet</code> 
1718     	 * which equals <code>mSet</code> but cannot be modified 
1719 	 * neither directly nor via its iterator. 
1720 	 *y
1721 	 * @throws NullPointerException
1722 	 *    if <code>coll==null</code>. 
1723    	 */
1724 	ImmutableSortedMultiSet(SortedMultiSet<E> mSet) {
1725 	    if (mSet == null) {
1726 		throw new NullPointerException(); // NOPMD
1727 	    }
1728 	    this.mSet = mSet;
1729 	}
1730 
1731 	ImmutableSortedMultiSet(Set<Modification> mods,
1732 				SortedMultiSet<E> mSet) {
1733 	    super(mods);
1734 	    if (mSet == null) {
1735 		throw new NullPointerException(); // NOPMD 
1736 	    }
1737 	    this.mSet = mSet;
1738 	}
1739 
1740     	/* ---------------------------------------------------------------- *
1741     	 * methods.                                                         *
1742     	 * ---------------------------------------------------------------- */
1743 
1744 	// ****
1745 	public SortedMultiSet<E> unrestricted() {
1746 	    return this.mSet;
1747 	}
1748 
1749 	public SortedSet<E> getSet() {
1750 	    return new ImmutableSortedSet<E>(allowedModifications(),
1751 					     unrestricted().getSet());
1752 	}
1753 
1754      	public NavigableMap<E, Multiplicity> getMap() {
1755 	    //return Collections
1756 	    //.unmodifiableNavigableMap(unrestricted().getMap())
1757 	    throw new NotYetImplementedException();
1758 	    // return new ImmutableNavigableMap(unrestricted().getMap());
1759 	}
1760 
1761 	public Comparator<? super E> comparator() {
1762 	    return unrestricted().comparator();
1763 	}
1764 
1765 	public E first() {
1766 	    return unrestricted().first();
1767 	}
1768 
1769 	public E last() {
1770 	    return unrestricted().last();
1771 	}
1772 
1773 	public SortedMultiSet<E> headSet(E toElement) {
1774 	    SortedMultiSet<E> res0 = unrestricted()
1775 		.headSet(toElement);
1776 	    return new ImmutableSortedMultiSet<E>(allowedModifications(), res0);
1777 	}
1778 
1779     	public SortedMultiSet<E> tailSet(E fromElement) {
1780 	    SortedMultiSet<E> res0 = unrestricted()
1781 		.tailSet(fromElement);
1782 	    return new ImmutableSortedMultiSet<E>(allowedModifications(), res0);
1783 	}
1784 
1785 	public SortedMultiSet<E> subSet(E fromElement, E toElement) {
1786 	    SortedMultiSet<E> res0 = unrestricted()
1787 		.subSet(fromElement, toElement);
1788 	    return new ImmutableSortedMultiSet<E>(allowedModifications(), res0);
1789 	}
1790 
1791     } // class ImmutableSortedMultiSet
1792 
1793 
1794     /* -------------------------------------------------------------------- *
1795      * class fields.                                                        *
1796      * -------------------------------------------------------------------- */
1797 
1798 
1799 
1800     /* -------------------------------------------------------------------- *
1801      * class methods.                                                       *
1802      * -------------------------------------------------------------------- */
1803 
1804 
1805     /**
1806      * Returns an unmodifiable view 
1807      * of the specified collection <code>coll</code>. 
1808      * This method allows modules to provide users 
1809      * with "read-only" access to internal collections. 
1810      * Query operations on the returned collection 
1811      * "read through" to the specified collection, 
1812      * and attempts to modify the returned collection, 
1813      * whether direct or via its iterator, 
1814      * result in an <code>UnsupportedOperationException</code>. 
1815      *
1816      * @param coll 
1817      *    an instance of a <code>Collection</code>. 
1818      * @return 
1819      *    a <code>Collection</code> which equals <code>coll</code>, 
1820      *    i.e. with the same elements 
1821      *    returned by the iterator in the same ordering 
1822      *    but is immutable. 
1823      *    Note that the return type offers methods 
1824      *    {@link CollectionsExt.ImmutableCollection
1825      *#allowModification(CollectionsExt.Modification)}, 
1826      *    {@link CollectionsExt.ImmutableCollection#allowedModifications()} 
1827      *    and {@link CollectionsExt.ImmutableCollection#unrestricted()}. 
1828      * @throws NullPointerException
1829      *    if <code>coll==null</code>. 
1830      */
1831     public static <E> ImmutableCollection<E> 
1832 	getImmutableCollection(Collection<E> coll) {
1833 	return new ImmutableCollection<E>(coll);
1834     }
1835 
1836     // as for {@link #getImmutableCollection(Collection)} 
1837     public static <E> ImmutableSet<E> getImmutableSet(Set<E> set) {
1838 	return new ImmutableSet<E>(set);
1839     }
1840 
1841     // as for {@link #getImmutableCollection(Collection)} 
1842     public static 
1843 	<E> ImmutableSortedSet<E> getImmutableSortedSet(SortedSet<E> set) {
1844 	return new ImmutableSortedSet<E>(set);
1845     }
1846 
1847     // as for {@link #getImmutableCollection(Collection)} 
1848     public static <E> ImmutableList<E> getImmutableList(List<E> list) {
1849 	return new ImmutableList<E>(list);
1850     }
1851 
1852     public static <E> CyclicList<E> getImmutableCyclicList(CyclicList<E> cyc) {
1853 	return new ImmutableCyclicList<E>(cyc);
1854     }
1855 
1856     public static 
1857 	<E> MultiSet<E> getImmutableMultiSet(MultiSet<E> mSet) {
1858 	return new ImmutableMultiSet<E>(mSet);
1859     }
1860 
1861     public static <E> 
1862 	MultiSet<E> getImmutableSortedMultiSet(SortedMultiSet<E> mSet) {
1863 	return new ImmutableMultiSet<E>(mSet);
1864     }
1865 
1866 
1867 
1868     /**
1869      * Retuns a weak hash set, i.e. a hash set of weak references. 
1870      *
1871      * @see java.util.HashMap
1872      * @see Collections#newSetFromMap(Map)
1873      */
1874     public static <E> Set<E> weakHashSet() {
1875 	return Collections.newSetFromMap(new WeakHashMap<E, Boolean>());
1876     }
1877 
1878     /**
1879      * Converts the list given recursively into an array. 
1880      *
1881      * @param list 
1882      *    a <code>List</code>. 
1883      * @return 
1884      *    an array <code>array</code> of objects satisfying 
1885      *    <code>array[i] == list.get(i)</code> 
1886      *    if <code>list.get(i)</code> is not a list; 
1887      *    <code>array[i] == recToArray(list.get(i))</code> otherwise. 
1888      *    Note that <code>array</code> may be a nested array 
1889      *    but that the dimension is always one. 
1890      * @see #recToArray(Object, Class)
1891      * @see ArraysExt#recAsList(Object[])
1892      */
1893     public static Object[] recToArray(List<?> list) {
1894 
1895 	Object[] result = new Object[list.size()];
1896 	int index = 0;
1897 	for (Object cand : list) {
1898 	    if (cand instanceof List) {
1899 		// cand is a list. 
1900 		result[index] = recToArray((List) cand);
1901 	    } else {
1902 		// cand is no list. 
1903 		result[index] = cand;
1904 	    }
1905 	    index++;
1906 	}
1907 	return result;
1908     }
1909 
1910     /**
1911      * Converts <code>source</code> 
1912      * which is typically a {@link java.util.List}, 
1913      * recursively into an array with the given type. 
1914      *
1915      * @param source
1916      *    an arbitrary <code>Object</code>, even an array 
1917      *    but typically a <code>List</code>. 
1918      * @param cls
1919      *    Up to compatibility 
1920      *    (see {@link BasicTypesCompatibilityChecker#areCompatible}), 
1921      *    the type of the return value. 
1922      *    Note that typically this is an array type 
1923      *    such as <code>Double[][][]</code> or <code>List[][][]</code> 
1924      *    or even <code>int[][][]</code> but this need not be the case. 
1925      * @return 
1926      *    <ul>
1927      *    <li>
1928      *    if <code>cls</code> and <code>source</code> are compatible 
1929      *    (see {@link BasicTypesCompatibilityChecker#areCompatible}), 
1930      *    e.g. if <code>source</code> is an instance of <code>cls</code> 
1931      *    or if <code>source == null</code>, 
1932      *    the object <code>source</code> is returned. 
1933      *    <p>
1934      *    If <code>cls</code> is not an elementary type 
1935      *    as e.g. {@link java.lang.Boolean#TYPE}, 
1936      *    and if <code>source != null</code>, 
1937      *    compatibility means that <code>source</code> 
1938      *    is an instance of the corresponding wrapper class. 
1939      *    <li>
1940      *    if <code>cls</code> and <code>source</code> are not compatible, 
1941      *    <code>cls</code> must be an array type 
1942      *    and <code>source</code> must be a list; 
1943      *    otherwise an exception is thrown. 
1944      *    <p>
1945      *    In the former case, 
1946      *    an array <code>array</code> of objects is returned 
1947      *    satisfying <code>array.length == ((List)source).size()</code> and 
1948      *    <code>array[i] == recToArray(list.get(i), cls2)</code> 
1949      *    for all valid indices <code>i</code> is returned. 
1950      *    The <code>cls2</code> argument for the recursive invocation 
1951      *    is the element type of <code>cls</code>. 
1952      *    <p>
1953      *    Note that although the return value is always an array, 
1954      *    its type need not be a subtype of <code>Object[]</code> 
1955      *    or of <code>Object[][]</code>. 
1956      *    Consider for instance the case 
1957      *    where <code>source</code> is a list of <code>Integer</code>s 
1958      *    and <code>cls</code> is <code>int[]</code>: 
1959      *    This yields an
1960      *    </ul>
1961      * @throws IllegalArgumentException
1962      *    if neither of the following is true: 
1963      *    <ul>
1964      *    <li>
1965      *    <code>cls</code> and <code>source</code> are compatible. 
1966      *    <li>
1967      *    <code>cls</code> is an array type and 
1968      *    <code>source</code> is a <code>List</code>. 
1969      *    </ul>
1970      * @see ArraysExt#recAsList(Object, Class)
1971      */
1972     public static Object recToArray(Object source, Class<?> cls) {
1973 	return recToArray(source, cls, Caster.BASIC_TYPES);
1974     }
1975 
1976     /**
1977      * Converts <code>source</code> 
1978      * which is typically a {@link java.util.Collection}, 
1979      * recursively into an array with the given type 
1980      * using the specified caster 
1981      * for the elementary objects in <code>source</code>. 
1982      *
1983      * @param source
1984      *    an arbitrary <code>Object</code>, even an array 
1985      *    but typically a <code>Collection</code>. 
1986      * @param cls
1987      *    Up to compatibility defined by <code>caster</code>, 
1988      *    the type of the return value. 
1989      *    Note that typically this is an array type 
1990      *    such as <code>Double[][][]</code> or <code>List[][][]</code> 
1991      *    or even <code>int[][][]</code> but this need not be the case. 
1992      *    Note that the base type 
1993      *    has to be compatible with the source objects 
1994      *    with respect to the specified <code>caster</code>. 
1995      * @param caster 
1996      *    performs the conversion of the top-level elements 
1997      *    of the <code>source</code>. 
1998      * @return 
1999      *    <ul>
2000      *    <li>
2001      *    if <code>cls</code> and <code>source</code> are compatible 
2002      *    (see {@link Caster#areCompatible}), 
2003      *    the {@link Caster#cast cast of} <code>source</code> is returned. 
2004      *    <p>
2005      *    Note that compatibility is up to wrapping of elementary types 
2006      *    and unwrapping of their wrappers. 
2007      *    <li>
2008      *    if <code>cls</code> and <code>source</code> are not compatible, 
2009      *    <code>cls</code> must be an array type 
2010      *    and <code>source</code> must be a list; 
2011      *    otherwise an exception is thrown. 
2012      *    <p>
2013      *    In the former case, 
2014      *    an array <code>array</code> of objects is returned 
2015      *    satisfying <code>array.length == ((Collection)source).size()</code> 
2016      *    and 
2017      *    <code>array[i] == recToArray(list.get(i), ... , caster)</code> 
2018      *    for all valid indices <code>i</code>. 
2019      *    The <code>cls2</code> argument for the recursive invocation 
2020      *    is the element type of <code>cls</code>. 
2021      *    <p>
2022      *    Note that although the return value 
2023      *    is either the result of a casting process or an array, 
2024      *    in the latter case its type need not be 
2025      *    a subtype of <code>Object[]</code> 
2026      *    or of <code>Object[][]</code>. 
2027      *    Consider for instance the case 
2028      *    where <code>source</code> is a list of <code>Integer</code>s 
2029      *    and <code>cls</code> is <code>int[]</code>: 
2030      *    </ul>
2031      * @throws IllegalArgumentException
2032      *    if neither of the following is true: 
2033      *    <ul>
2034      *    <li>
2035      *    <code>cls</code> and <code>source</code> are compatible 
2036      *    with respect to {@link Caster#areCompatible caster}. 
2037      *    <li>
2038      *    <code>cls</code> is an array type and 
2039      *    <code>source</code> is a <code>List</code>. 
2040      *    </ul>
2041      * @see ArraysExt#recAsList(Object, Class, Caster)
2042      */
2043     public static Object recToArray(Object source, 
2044 				    Class<?> cls, 
2045 				    Caster caster) {
2046 
2047 	if (caster.areCompatible(cls, source)) {
2048 	    // Here, either source == null || cls.isInstance(source) 
2049 	    // or source wraps something of type cls. 
2050 	    return caster.cast(source);
2051 	}
2052 	// Here, source is not compatible with cls. 
2053 
2054 	if (!cls.isArray()) {
2055 	    // Here, the result type is not an array type. 
2056 	    throw new IllegalArgumentException
2057 		("Found incompatible types: " + source + 
2058 		 " is not an instance of " + cls + 
2059 		 " but of " + source.getClass() + ". ");
2060 	}
2061 
2062 	// Here, the result type is an array type. 
2063 	if (!(source instanceof Collection)) {
2064 	    throw new IllegalArgumentException
2065 		("Found incompatible types: " + source + 
2066 		 " is not an instance of List. ");
2067 	}
2068 	// Here, source instanceof Collection and cls.isArray(). 
2069 
2070 	Collection<?> coll = (Collection<?>) source;
2071 	Class<?> compType = cls.getComponentType();
2072 	Object result = Array.newInstance(compType, coll.size());
2073 	int ind = 0;
2074 	for (Object cand : coll) {
2075 	    // automatic unwrapping if needed. 
2076 	    Array.set(result, ind++, recToArray(cand, compType, caster));
2077 	}
2078 	return result;
2079     }
2080 
2081     /*
2082      * Fills the given map with key-value pairs given by <code>keyVal</code> 
2083      * and returns a trace of the replaced objects. 
2084      * Note that this method is misplaced in this class but .... 
2085      *
2086      * @param map 
2087      *    a <code>Map</code> object. 
2088      * @param keyVal 
2089      *    an array of key-value pairs. 
2090      *    In particular, <code>keyVal[i].length == 2</code> whenever defined. 
2091      * @return 
2092      *    an array of key-value pairs. 
2093      *    An entry <code>new Object[] {key,value}</code> means, 
2094      *    that before invoking this method, 
2095      *    <code>map.get(key) == value</code> hold. 
2096      *    Note that <code>value == null</code> is possible. 
2097      * @throws ClassCastException 
2098      *    if an element of an entry <code>new Object[] {key, value}</code> 
2099      *    of <code>keyVal</code> has not the right type. 
2100      */
2101 /*
2102     public static <K, V> Object[][] fillMap(Map<K, V> map, Object[][] keyVal) {
2103 	List<Object[]> replaced = new ArrayList<Object[]>();
2104 	V repl;
2105 	for (int i = 0; i < keyVal.length; i++) {
2106 	    repl = map.put((K)keyVal[i][0], (V)keyVal[i][1]);
2107 	    if (map.keySet().contains(keyVal[i][0])) {
2108 		replaced.add(new Object[] {keyVal[i][0], repl});
2109 	    }
2110 	}
2111 	return (Object[][])replaced.toArray(new Object[][] {});
2112     }
2113 */
2114 
2115     /**
2116      * Returns the unique element of the collection <code>coll</code>. 
2117      *
2118      * @param coll
2119      *    a collection of <code>T</code>'s. 
2120      * @return
2121      *    the unique element of the collection <code>coll</code>. 
2122      * @throws IllegalStateException
2123      *    if <code>coll</code> does not contain a unique element. 
2124      */
2125     public static <T> T getUnique(Collection<? extends T> coll) {
2126 	if (coll.size() != 1) {
2127 	    throw new IllegalStateException
2128 		("Expected a single element; found collection " + coll + ". ");
2129 	}
2130 	assert !coll.isEmpty();
2131 
2132 	return coll.iterator().next();
2133 	// for (T res : coll) {
2134 	//     return res;
2135 	// }
2136 	// This place is never reached, because coll is not empty 
2137 	//throw new IllegalStateException();
2138     }
2139 
2140     /**
2141      * Returns the reverse of the given list. 
2142      * In fact the list returned is an {@link java.util.ArrayList}. 
2143      */
2144     public static <T> List<T> reverse(List<T> list) {
2145 	List<T> res = new ArrayList<T>(list.size());
2146 	// NOPMD
2147 	for (int i = 0; i < list.size(); i++) {// NOPMD
2148 	    res.add(list.get(list.size() - 1 - i));
2149 	}
2150 	return res;
2151     }
2152 
2153     public static void main(String[] args) {
2154     }
2155 
2156 }
2157 
2158