1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package com.sun.star.lib.uno.helper;
25 import java.util.Iterator;
26 import java.util.ListIterator;
27 import java.util.NoSuchElementException;
28 import java.util.Collection;
29 import com.sun.star.lang.EventObject;
30 import com.sun.star.lang.XEventListener;
31 import com.sun.star.uno.UnoRuntime;
32 
33 /**
34  * This class is a container for interfaces.
35  *
36  * It is intended to be used as storage for UNO interface of a specific type.
37  * The client has to ensure that the container contains only elements of the same
38  * type. If one needs to store different types, then one uses OMultiTypeInterfaceContainer.
39  * When the client calls disposeAndClear, the contained objects are queried for
40  * com.sun.star.lang.XEventListener and disposing is called. Afterwards
41  * the list cannot be used anymore.
42  *
43  * This list does not allow null values.
44  * All methods are thread-safe. The same holds true for
45  * iterators, issued by this class. Several iterators can exist at the same time and can also
46  * be modified (java.util.ListIterator.add, java.util.ListIterator.remove etc.). To make this work,
47  * the InterfaceContainer provides the iterators with copys of the list's data.
48  * The add and remove calls on the iterator modify the data in the iterator's list as well as
49  * in InterfaceContainer. Modification on InterfaceContainer, however, are not
50  * synchronized with existing iterators. For example
51  * <pre>
52  * InterfaceContainer cont= new InterfaceContainer();
53  * ListIterator it= cont.listIterator();
54  *
55  * cont.add( someInterface);
56  * // one cannot obtain someInterface through iterator it,
57  * // instead get a new iterator
58  * it= cont.listIterator();
59  * // it now keeps a fresh copy of cont and hence contains someInterface
60  *
61  * // Adding an interface on the iterator will cause the interface also to be added
62  * // to InterfaceContainer
63  * it.add( someOtherInterface);
64  * // someOtherInterface is now in it and cont
65  * ListIterator it2= cont.listIterator();
66  * //someOtherInterface can also be obtained by all newly created iterators, e.g. it2.
67  * </pre>
68  *
69  *  The add and remove methods of an iterator work on a particular location within a list,
70  *  dependent on what the value of the iterator's cursor is. After the call the value at the
71  *  appropriate position has been modified. Since the iterator received a copy of InterfaceContainer's
72  *  data, InterfaceContainer may have been modified (by List methods or through other iterators).
73  *  Therefore both data sets may not contain the same elements anymore. Consequently, a List method
74  *  that modifies data, does not modify InterfaceContainer's data at a certain index
75  *  (according to the iterators cursor). Instead, new elements are added at the end of list. When
76  *  Iterator.remove is called, then the first occurrence of that element in InterfaceContainer
77  *  is removed.
78  *  ListIterator.set is not supported.
79  *
80  * A lot of  methods resemble those of the  to java.util.List interface, although
81  * this class does not implement it. However, the list iterators returned, for example by
82  * the listIterator method implement the java.util.ListIterator interface.
83  * Implementing the List interface would mean to support all none - optional methods as
84  * prescribed by the interface declaration. Among those is the subList method which returns
85  * a range of values of the list's data wrapped in a List implementation. Changes to the sub
86  * list have to cause changes in the main list. This is a problem, since this class is to be
87  * used in a multi-threaded environment. The sub list could work on a copy as the iterators
88  * do, but all the functions which work on an given index could not be properly supported.
89  * Unfortunately, the List interface documentation states that all optional methods implemented
90  * by the list have to be implemented in the sub list. That would mean to do without all those
91  * critical methods, although they might work well in the "main list" (as opposed to sub list).
92  */
93 public class InterfaceContainer implements Cloneable
94 {
95     final boolean DEBUG= false;
96     /**
97      * The array buffer into which the elements of the ArrayList are stored.
98      * The capacity of the ArrayList is the length of this array buffer.
99      */
100     Object elementData[];
101 
102     /**
103      * The size of the ArrayList (the number of elements it contains).
104      */
105     private int size;
106 
107 
108     //private ArrayList data= new ArrayList();
109     /** Creates a new instance of InterfaceContainer */
InterfaceContainer()110     public InterfaceContainer()
111     {
112         this(10);
113     }
114     /**
115      * Constructs an empty list with the specified initial capacity.
116      *
117      * @param   initialCapacity   the initial capacity of the list.
118      * @exception IllegalArgumentException if the specified initial capacity
119      *            is negative
120      */
InterfaceContainer(int initialCapacity)121     public InterfaceContainer(int initialCapacity)
122     {
123         if (initialCapacity < 0)
124             throw new java.lang.IllegalArgumentException("Illegal Capacity: "+
125             initialCapacity);
126         this.elementData = new Object[initialCapacity];
127     }
128 
129     /**
130      * Trims the capacity of this <tt>ArrayList</tt> instance to be the
131      * list's current size.  An application can use this operation to minimize
132      * the storage of an <tt>ArrayList</tt> instance.
133      */
trimToSize()134     synchronized public void trimToSize()
135     {
136         int oldCapacity = elementData.length;
137         if (size < oldCapacity)
138         {
139             Object oldData[] = elementData;
140             elementData = new Object[size];
141             System.arraycopy(oldData, 0, elementData, 0, size);
142         }
143     }
144 
145     /**
146      * Increases the capacity of this <tt>ArrayList</tt> instance, if
147      * necessary, to ensure  that it can hold at least the number of elements
148      * specified by the minimum capacity argument.
149      *
150      * @param   minCapacity   the desired minimum capacity.
151      */
ensureCapacity(int minCapacity)152     synchronized public void ensureCapacity(int minCapacity)
153     {
154         int oldCapacity = elementData.length;
155         if (minCapacity > oldCapacity)
156         {
157             Object oldData[] = elementData;
158             int newCapacity = (oldCapacity * 3)/2 + 1;
159             if (newCapacity < minCapacity)
160                 newCapacity = minCapacity;
161             elementData = new Object[newCapacity];
162             System.arraycopy(oldData, 0, elementData, 0, size);
163         }
164     }
165 
166     /**
167      * Appends the specified element to the end of this list.
168      *
169      * @param o element to be appended to this list.
170      * @return <tt>true</tt> (as per the general contract of Collection.add).
171      */
add(Object o)172     synchronized public boolean add(Object o)
173     {
174         boolean ret= false;
175         if (elementData != null && o != null)
176         {
177             ensureCapacity(size + 1);  // Increments modCount!!
178             elementData[size++] = o;
179             ret= true;
180         }
181         return ret;
182     }
183 
184     /**
185      * Inserts the specified element at the specified position in this
186      * list. Shifts the element currently at that position (if any) and
187      * any subsequent elements to the right (adds one to their indices).
188      *
189      * @param index index at which the specified element is to be inserted.
190      * @param element element to be inserted.
191      * @throws    IndexOutOfBoundsException if index is out of range
192      *		  <tt>(index &lt; 0 || index &gt; size())</tt>.
193      */
add(int index, Object element)194     synchronized public void add(int index, Object element)
195     {
196         if (elementData != null && element != null)
197         {
198             if (index > size || index < 0)
199                 throw new IndexOutOfBoundsException(
200                 "Index: "+index+", Size: "+size);
201 
202             ensureCapacity(size+1);
203             System.arraycopy(elementData, index, elementData, index + 1,
204             size - index);
205             elementData[index] = element;
206             size++;
207         }
208     }
209 
210 
211     /**
212      * Appends all of the elements in the specified Collection to the end of
213      * this list, in the order that they are returned by the
214      * specified Collection's Iterator.  The behavior of this operation is
215      * undefined if the specified Collection is modified while the operation
216      * is in progress.  (This implies that the behavior of this call is
217      * undefined if the specified Collection is this list, and this
218      * list is nonempty.)
219      *
220      * @param c the elements to be inserted into this list.
221      * @throws    IndexOutOfBoundsException if index out of range <tt>(index
222      *		  &lt; 0 || index &gt; size())</tt>.
223      */
addAll(Collection c)224     synchronized public boolean addAll(Collection c)
225     {
226         int numNew = c.size();
227         ensureCapacity(size + numNew);
228 
229         Iterator e = c.iterator();
230         for (int i=0; i<numNew; i++)
231         {
232             Object o= e.next();
233             if (o != null)
234                 elementData[size++] = o;
235         }
236         return numNew != 0;
237     }
238     /**
239      * Inserts all of the elements in the specified Collection into this
240      * list, starting at the specified position.  Shifts the element
241      * currently at that position (if any) and any subsequent elements to
242      * the right (increases their indices).  The new elements will appear
243      * in the list in the order that they are returned by the
244      * specified Collection's iterator.
245      *
246      * @param index index at which to insert first element
247      *		    from the specified collection.
248      * @param c elements to be inserted into this list.
249      * @throws    IndexOutOfBoundsException if index out of range <tt>(index
250      *		  &lt; 0 || index &gt; size())</tt>.
251      */
addAll(int index, Collection c)252     synchronized public boolean addAll(int index, Collection c)
253     {
254         boolean ret= false;
255         if (elementData != null)
256         {
257             if (index > size || index < 0)
258                 throw new IndexOutOfBoundsException(
259                 "Index: "+index+", Size: "+size);
260             // only add  the non-null elements
261             int sizeCol= c.size();
262             Object[] arColl= new Object[sizeCol];
263             Iterator icol= c.iterator();
264             int curIndex= 0;
265             for (int i=0; i < sizeCol; i++)
266             {
267                 Object o= icol.next();
268                 if (o != null)
269                     arColl[curIndex++]= o;
270             }
271             int numNew = curIndex;
272             ensureCapacity(size + numNew);  // Increments modCount!!
273 
274             int numMoved = size - index;
275             if (numMoved > 0)
276                 System.arraycopy(elementData, index, elementData, index + numNew,
277                 numMoved);
278 
279             for (int i=0; i<numNew; i++)
280             {
281                 elementData[index++]= arColl[i];
282             }
283             size += numNew;
284             ret= numNew != 0;
285         }
286         return ret;
287     }
288 
289     /**
290      * Removes all of the elements from this list.  The list will
291      * be empty after this call returns.
292      */
clear()293     synchronized public void clear()
294     {
295         if (elementData != null)
296         {
297             // Let gc do its work
298             for (int i = 0; i < size; i++)
299                 elementData[i] = null;
300 
301             size = 0;
302         }
303     }
304     /**
305      * Returns <tt>true</tt> if this list contains the specified element.
306      *
307      * @param elem element whose presence in this List is to be tested.
308      */
contains(Object elem)309     synchronized public boolean contains(Object elem)
310     {
311         return indexOf(elem) >= 0;
312     }
313 
containsAll(Collection collection)314     synchronized public boolean containsAll(Collection collection)
315     {
316         boolean retVal= true;
317         if (elementData != null && collection != null)
318         {
319             Iterator it= collection.iterator();
320             while (it.hasNext())
321             {
322                 Object obj= it.next();
323                 if (false == contains(obj))
324                 {
325                     retVal= false;
326                     break;
327                 }
328             }
329         }
330         return retVal;
331     }
332     /**
333      * Returns the element at the specified position in this list.
334      *
335      * @param  index index of element to return.
336      * @return the element at the specified position in this list.
337      * @throws    IndexOutOfBoundsException if index is out of range <tt>(index
338      * 		  &lt; 0 || index &gt;= size())</tt>.
339      */
get(int index)340     synchronized public Object get(int index)
341     {
342         if (elementData != null)
343         {
344             RangeCheck(index);
345             return elementData[index];
346         }
347         return null;
348     }
349 
350     /**
351      * Searches for the first occurrence of the given argument, testing
352      * for equality using the <tt>equals</tt> method.
353      *
354      * @param   elem   an object.
355      * @return  the index of the first occurrence of the argument in this
356      *          list; returns <tt>-1</tt> if the object is not found.
357      * @see     Object#equals(Object)
358      */
indexOf(Object elem)359     synchronized public int indexOf(Object elem)
360     {
361         int index= -1;
362         if (elementData != null && elem != null)
363         {
364             for (int i = 0; i < size; i++)
365             {
366                 if (elem == elementData[i])
367                 {
368                     index= i;
369                     break;
370                 }
371             }
372 
373             if (index == -1)
374             {
375                 for (int i = 0; i < size; i++)
376                 {
377                     if (UnoRuntime.areSame(elem, elementData[i]))
378                     {
379                         index= i;
380                         break;
381                     }
382                 }
383             }
384         }
385         return index;
386     }
387     /**
388      * Tests if this list has no elements.
389      *
390      * @return  <tt>true</tt> if this list has no elements;
391      *          <tt>false</tt> otherwise.
392      */
isEmpty()393     synchronized public boolean isEmpty()
394     {
395         return size == 0;
396     }
397 
iterator()398     synchronized public Iterator iterator()
399     {
400         if (elementData != null)
401         {
402             InterfaceContainer aCopy= (InterfaceContainer) clone();
403             return new Itr(aCopy);
404         }
405         return null;
406     }
407     /**
408      * Returns the index of the last occurrence of the specified object in
409      * this list.
410      *
411      * @param   elem   the desired element.
412      * @return  the index of the last occurrence of the specified object in
413      *          this list; returns -1 if the object is not found.
414      */
lastIndexOf(Object elem)415     synchronized public int lastIndexOf(Object elem)
416     {
417         int index= -1;
418         if (elementData != null && elem != null)
419         {
420             for (int i = size-1; i >= 0; i--)
421             {
422                 if (elem == elementData[i])
423                 {
424                     index= i;
425                     break;
426                 }
427             }
428             if (index == -1)
429             {
430                 for (int i = size-1; i >= 0; i--)
431                 {
432                     if (UnoRuntime.areSame(elem, elementData[i]))
433                     {
434                         index= i;
435                         break;
436                     }
437                 }
438             }
439         }
440         return index;
441     }
442 
443     /**
444      * Returns a shallow copy of this <tt>ArrayList</tt> instance. The contained
445      * references are copied but the objects not.
446      *
447      * @return  a clone of this <tt>List</tt> instance.
448      */
clone()449     synchronized public Object clone()
450     {
451         Object ret= null;
452         if (elementData != null)
453         {
454             InterfaceContainer cont= new InterfaceContainer();
455             cont.elementData = new Object[size];
456             cont.size= size;
457             System.arraycopy(elementData, 0, cont.elementData, 0, size);
458             ret= cont;
459         }
460         return ret;
461     }
listIterator()462     synchronized public ListIterator listIterator()
463     {
464         return listIterator(0);
465     }
466 
467     /** The iterator keeps a copy of the list. Changes to InterfaceContainer do not
468      *  affect the data of the iterator. Conversly, changes to the iterator are effect
469      *  InterfaceContainer.
470      *
471      * @param index
472      */
listIterator(int index)473     synchronized public ListIterator listIterator(int index)
474     {
475         if (elementData != null)
476         {
477             InterfaceContainer aCopy= (InterfaceContainer) clone();
478             return new LstItr(aCopy, index);
479         }
480         return null;
481     }
482     /**
483      * Removes the element at the specified position in this list.
484      * Shifts any subsequent elements to the left (subtracts one from their
485      * indices).
486      *
487      * @param index the index of the element to removed.
488      * @return the element that was removed from the list.
489      * @throws    IndexOutOfBoundsException if index out of range <tt>(index
490      * 		  &lt; 0 || index &gt;= size())</tt>.
491      */
remove(int index)492     synchronized public Object remove(int index)
493     {
494         Object ret= null;
495         if (elementData != null)
496         {
497             RangeCheck(index);
498             ret= elementData[index];
499 
500             int numMoved = size - index - 1;
501             if (numMoved > 0)
502                 System.arraycopy(elementData, index+1, elementData, index,
503                 numMoved);
504             elementData[--size] = null; // Let gc do its work
505         }
506         return ret;
507     }
508 
509 
510     /** Parameter obj may  */
remove(Object obj)511     synchronized public boolean remove(Object obj)
512     {
513         boolean ret= false;
514         if (elementData != null && obj != null)
515         {
516             int index= indexOf(obj);
517             if (index != -1)
518             {
519                 ret= true;
520                 remove(index);
521             }
522         }
523         return ret;
524     }
525 
removeAll(Collection collection)526     synchronized public boolean removeAll(Collection collection)
527     {
528         boolean retVal= false;
529         if (elementData != null && collection != null)
530         {
531             Iterator it= collection.iterator();
532             while (it.hasNext())
533             {
534                 Object obj= it.next();
535                 boolean bMod= remove( obj);
536                 if (bMod)
537                     retVal= true;
538             }
539         }
540         return retVal;
541     }
542 
retainAll(Collection collection)543     synchronized public boolean retainAll(Collection collection)
544     {
545         boolean retVal= false;
546         if (elementData != null && collection != null)
547         {
548             // iterate over data
549             Object[] arRetained= new Object[size];
550             int indexRetained= 0;
551             for(int i= 0; i < size; i++)
552             {
553                 Object curElem= elementData[i];
554                 // try to find the element in collection
555                 Iterator itColl= collection.iterator();
556                 boolean bExists= false;
557                 while (itColl.hasNext())
558                 {
559                     if (curElem == itColl.next())
560                     {
561                         // current element is in collection
562                         bExists= true;
563                         break;
564                     }
565                 }
566                 if (bExists == false)
567                 {
568                     itColl= collection.iterator();
569                     while (itColl.hasNext())
570                     {
571                         Object o= itColl.next();
572                         if (o != null)
573                         {
574                             if (UnoRuntime.areSame(o, curElem))
575                             {
576                                 bExists= true;
577                                 break;
578                             }
579                         }
580                     }
581                 }
582                 if (bExists == true)
583                     arRetained[indexRetained++]= curElem;
584             }
585             retVal= size != indexRetained;
586             if (indexRetained > 0)
587             {
588                 elementData= arRetained;
589                 size= indexRetained;
590             }
591         }
592         return retVal;
593     }
594 
595 
596     /** Not supported.
597      * @param index index of element to replace.
598      * @param element element to be stored at the specified position.
599      * @return the element previously at the specified position.
600      * @throws    IndexOutOfBoundsException if index out of range
601      *		  <tt>(index &lt; 0 || index &gt;= size())</tt>.
602      */
set(int index, Object element)603     synchronized public Object set(int index, Object element)
604     {
605           Object ret= null;
606           if (elementData != null && element != null)
607           {
608               RangeCheck(index);
609               ret = elementData[index];
610               elementData[index] = element;
611           }
612           return ret;
613     }
614 
615     /**
616      * Returns the number of elements in this list.
617      *
618      * @return  the number of elements in this list.
619      */
size()620     synchronized public int size()
621     {
622         if (elementData != null)
623             return size;
624         return 0;
625     }
626 
627 
628     /**
629      * Returns an array containing all of the elements in this list
630      * in the correct order.
631      *
632      * @return an array containing all of the elements in this list
633      * 	       in the correct order.
634      */
toArray()635     synchronized public Object[] toArray()
636     {
637         if (elementData != null)
638         {
639             Object[] result = new Object[size];
640             System.arraycopy(elementData, 0, result, 0, size);
641             return result;
642         }
643         return null;
644     }
645 
646     /**
647      * Returns an array containing all of the elements in this list in the
648      * correct order.  The runtime type of the returned array is that of the
649      * specified array.  If the list fits in the specified array, it is
650      * returned therein.  Otherwise, a new array is allocated with the runtime
651      * type of the specified array and the size of this list.<p>
652      *
653      * If the list fits in the specified array with room to spare (i.e., the
654      * array has more elements than the list), the element in the array
655      * immediately following the end of the collection is set to
656      * <tt>null</tt>.  This is useful in determining the length of the list
657      * <i>only</i> if the caller knows that the list does not contain any
658      * <tt>null</tt> elements.
659      *
660      * @param a the array into which the elements of the list are to
661      *		be stored, if it is big enough; otherwise, a new array of the
662      * 		same runtime type is allocated for this purpose.
663      * @return an array containing the elements of the list.
664      * @throws ArrayStoreException if the runtime type of a is not a supertype
665      *         of the runtime type of every element in this list.
666      */
toArray(Object a[])667     synchronized public Object[] toArray(Object a[])
668     {
669         if (a.length < size)
670             a = (Object[])java.lang.reflect.Array.newInstance(
671             a.getClass().getComponentType(), size);
672         if (elementData != null)
673             System.arraycopy(elementData, 0, a, 0, size);
674 
675         if (a.length > size)
676             a[size] = null;
677 
678         return a;
679     }
680 
681     /**
682      * Check if the given index is in range.  If not, throw an appropriate
683      * runtime exception.
684      */
RangeCheck(int index)685     private void RangeCheck(int index)
686     {
687         if (index >= size || index < 0)
688             throw new IndexOutOfBoundsException(
689             "Index: "+index+", Size: "+size);
690     }
691 
disposeAndClear(EventObject evt)692     public void disposeAndClear(EventObject evt)
693     {
694         Iterator aIt;
695         synchronized (this)
696         {
697             aIt= iterator();
698             // Container freigeben, falls im disposing neue Eintraege kommen
699             // set the member to null, the iterator delete the values
700             clear();
701             elementData= null;
702             size= 0;
703         }
704         if (aIt != null)
705         {
706             while( aIt.hasNext() )
707             {
708                 try
709                 {
710                     Object o= aIt.next();
711                     XEventListener evtListener= UnoRuntime.queryInterface(
712                     XEventListener.class, o);
713                     if( evtListener != null )
714                         evtListener.disposing( evt );
715                 }
716                 catch ( RuntimeException e)
717                 {
718                     // be robust, if e.g. a remote bridge has disposed already.
719                     // there is no way, to delegate the error to the caller :o(.
720                 }
721             }
722         }
723     }
724 
725 
726     private class Itr implements Iterator
727     {
728         InterfaceContainer dataIt;
729         /**
730          * Index of element to be returned by subsequent call to next.
731          */
732         int cursor= 0;
733         /**
734          * Index of element returned by most recent call to next or
735          * previous.  Reset to -1 if this element is deleted by a call
736          * to remove.
737          */
738         int lastRet = -1;
739 
740         /** The object that has been returned by most recent call to next
741          *  or previous. Reset to null if this element is deleted by a call
742          *  to remove.
743          */
744         Object lastRetObj= null;
745 
Itr(InterfaceContainer _data)746         Itr(InterfaceContainer _data)
747         {
748             dataIt= _data;
749         }
750 
hasNext()751         synchronized public boolean hasNext()
752         {
753             return cursor !=dataIt.size();
754         }
755 
next()756         public synchronized Object next()
757         {
758             try
759             {
760                 Object next = dataIt.get(cursor);
761                 lastRet = cursor++;
762                 lastRetObj= next;
763                 return next;
764             }
765             catch(java.lang.IndexOutOfBoundsException e)
766             {
767                 throw new java.util.NoSuchElementException();
768             }
769         }
770 
771         /** Removes the interface from the list, that has been last returned by a
772          *  call to next(). This is done according to the specification of the interface
773          *  method. The element is also removed from InterfaceContainer but independent
774          *  of the location. If the element is multiple times in InterfaceContainer then
775          *  it is up to the java.util.ArrayList implementation what element is removed.
776          */
remove()777         public synchronized void remove()
778         {
779             if (lastRet == -1)
780                 throw new IllegalStateException();
781             // Remove the entry from InterfaceContainer.
782             InterfaceContainer.this.remove(lastRetObj);
783             dataIt.remove(lastRet);
784 
785             if (lastRet < cursor)
786                 cursor--;
787             lastRet = -1;
788             lastRetObj= null;
789         }
790     }
791 
792     private class LstItr extends Itr implements ListIterator
793     {
794 
LstItr(InterfaceContainer _data, int _index)795         LstItr(InterfaceContainer _data, int _index)
796         {
797             super(_data);
798             cursor= _index;
799         }
800 
801         /** Inserts an element to the iterators list according to the specification
802          *  of this interface method. The element is also added to InterfaceContainer
803          *  but its location within the list cannot be guaranteed.
804          */
add(Object o)805         public synchronized void add(Object o)
806         {
807             InterfaceContainer.this.add(o);
808             dataIt.add(cursor++, o);
809             lastRet = -1;
810             lastRetObj= null;
811         }
812 
hasPrevious()813         synchronized public boolean hasPrevious()
814         {
815             return cursor != 0;
816         }
817 
nextIndex()818         synchronized public int nextIndex()
819         {
820             return cursor;
821         }
822 
previous()823         public synchronized Object previous()
824         {
825             try
826             {
827                 Object previous = dataIt.get(--cursor);
828                 lastRet = cursor;
829                 lastRetObj= previous;
830                 return previous;
831             } catch(IndexOutOfBoundsException e)
832             {
833                 throw new NoSuchElementException();
834             }
835         }
836 
previousIndex()837         synchronized public int previousIndex()
838         {
839             return cursor-1;
840         }
841 
842         /** This is not possible since several iterators can modify InterfaceContainer
843          */
set(Object o)844         public synchronized void set(Object o)
845         {
846             throw new UnsupportedOperationException();
847         }
848 
849 
850     } // class LstItr
851 }
852 
853