1   /* ListType
2    *
3    * $Id: ListType.java 4648 2006-09-25 16:25:53Z paul_jack $
4    *
5    * Created on Jan 7, 2004
6    *
7    * Copyright (C) 2004 Internet Archive.
8    *
9    * This file is part of the Heritrix web crawler (crawler.archive.org).
10   *
11   * Heritrix is free software; you can redistribute it and/or modify
12   * it under the terms of the GNU Lesser Public License as published by
13   * the Free Software Foundation; either version 2.1 of the License, or
14   * any later version.
15   *
16   * Heritrix is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU Lesser Public License for more details.
20   *
21   * You should have received a copy of the GNU Lesser Public License
22   * along with Heritrix; if not, write to the Free Software
23   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24   */
25  package org.archive.crawler.settings;
26  
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.ListIterator;
32  
33  import org.archive.util.SubList;
34  
35  /*** Super type for all lists.
36   *
37   * @author John Erik Halse
38   */
39  public abstract class ListType<T> extends Type implements List<Object> {
40  
41      private final List<T> listData = new ArrayList<T>();
42      private final String description;
43  
44      /*** Constructs a new ListType.
45       *
46       * @param name the name of the list
47       * @param description the description of the list
48       */
49      public ListType(String name, String description) {
50          super(name, null);
51          this.description = description;
52      }
53  
54      /*** Appends the specified element to the end of this list.
55       *
56       * @param element element to be appended to this list.
57       * @throws ClassCastException is thrown if the element was of wrong type
58       *         and could not be converted.
59       * @return true if this collection changed as a result of the call (as
60       * per the Collections.add contract).
61       */
62      public boolean add(Object element) {
63          T checked = checkType(element);
64          return this.listData.add(checked);
65      }
66  
67      /*** Inserts the specified element at the specified position in this list.
68       *
69       * Shifts the element currently at that position (if any) and any
70       * subsequent elements to the right (adds one to their indices).
71       *
72       * @param index index at which the specified element is to be inserted.
73       * @param element element to be inserted.
74       * @throws ClassCastException is thrown if the element was of wrong type
75       *         and could not be converted.
76       */
77      public void add(int index, Object element) {
78          T checked = checkType(element);
79          this.listData.add(index, checked);
80      }
81  
82      /*** Appends all of the elements in the specified list to the end of this
83       * list, in the order that they are returned by the specified lists's
84       * iterator.
85       *
86       * The behavior of this operation is unspecified if the specified
87       * collection is modified while the operation is in progress.
88       *
89       * This method is a helper method for subclasses.
90       *
91       * @param l list whose elements are to be added to this list.
92       */
93      protected void addAll(ListType<T> l) {
94          this.listData.addAll(l.listData);
95      }
96  
97      /*** Replaces the element at the specified position in this list with the
98       *  specified element.
99       *
100      * @param index index at which the specified element is to be inserted.
101      * @param element element to be inserted.
102      * @return the element previously at the specified position.
103      * @throws ClassCastException is thrown if the element was of wrong type
104      *         and could not be converted.
105      */
106     public Object set(int index, Object element) {
107         T checked = checkType(element);
108         return this.listData.set(index, checked);
109     }
110 
111     /*** Returns an iterator over the elements in this list in proper sequence.
112      *
113      * @return an iterator over the elements in this list.
114      */
115     public Iterator<Object> iterator() {
116         return new ListIter();
117     }
118 
119     /*** Get the number of elements in this list.
120      *
121      * @return number of elements.
122      */
123     public int size() {
124         return this.listData.size();
125     }
126 
127     /*** Returns true if this list contains no elements.
128      *
129      * @return true if this list contains no elements.
130      */
131     public boolean isEmpty() {
132         return this.listData.isEmpty();
133     }
134 
135     /*** Check if element is of right type for this list.
136      *
137      * If this method gets a String, it should try to convert it to
138      * the right element type before throwing an exception.
139      *
140      * @param element element to check.
141      * @return element of the right type.
142      * @throws ClassCastException is thrown if the element was of wrong type
143      *         and could not be converted.
144      */
145     public abstract T checkType(Object element) throws ClassCastException;
146 
147     /* (non-Javadoc)
148      * @see org.archive.crawler.settings.Type#getDefaultValue()
149      */
150     public Object getDefaultValue() {
151         return this;
152     }
153 
154     /* (non-Javadoc)
155      * @see org.archive.crawler.settings.Type#getDescription()
156      */
157     public String getDescription() {
158         return this.description;
159     }
160 
161     /*** Removes all elements from this list.
162      */
163     public void clear() {
164         this.listData.clear();
165     }
166 
167     /***
168      * Returns the object stored at the index specified
169      * @param index The location of the object to get within the list.
170      * @return the object stored at the index specified
171      */
172     public Object get(int index){
173         return this.listData.get(index);
174     }
175 
176     /*** The getLegalValues is not applicable for list so this method will
177      * always return null.
178      *
179      * @return null
180      * @see org.archive.crawler.settings.Type#getLegalValues()
181      */
182     public Object[] getLegalValues() {
183         return null;
184     }
185 
186     /*** Returns this object.
187      *
188      * This method is implemented to be able to treat the ListType as an
189      * subclass of {@link javax.management.Attribute}.
190      *
191      * @return this object.
192      * @see javax.management.Attribute#getValue()
193      */
194     public Object getValue() {
195         return this;
196     }
197 
198     public boolean addAll(Collection<? extends Object> c)
199     {
200     	for (Object o : c) {
201             T checked = checkType(o);
202             listData.add(checked);
203         }
204         return true;
205     }
206 
207     public boolean addAll(int index, Collection<? extends Object> c)
208     {
209     	for (Object o : c) {
210             T checked = checkType(o);
211             listData.add(index, checked);
212             index++;
213         }
214         return true;
215     }
216 
217     public boolean contains(Object o)
218     {
219         return this.listData.contains(o);
220     }
221 
222     public boolean containsAll(Collection c)
223     {
224         return this.listData.containsAll(c);
225     }
226 
227     public int indexOf(Object o)
228     {
229         return this.listData.indexOf(o);
230     }
231 
232     public int lastIndexOf(Object o)
233     {
234         return this.listData.lastIndexOf(o);
235     }
236 
237     public ListIterator<Object> listIterator()
238     {
239         return new ListIter();
240     }
241 
242     public ListIterator<Object> listIterator(int index)
243     {
244     	return new ListIter(index);
245     }
246 
247     public List<Object> subList(int fromIndex, int toIndex)
248     {
249         return new SubList<Object>(this, fromIndex, toIndex);
250     }
251 
252     public Object[] toArray()
253     {
254         return this.listData.toArray();
255     }
256 
257     public <X> X[] toArray(X[] a)
258     {
259         return this.listData.toArray(a);
260     }
261 
262     public Object remove(int index)
263     {
264         return this.listData.remove(index);
265     }
266 
267     public boolean remove(Object o)
268     {
269         return this.listData.remove(o);
270     }
271 
272     public boolean removeAll(Collection c)
273     {
274         return this.listData.removeAll(c);
275     }
276 
277     public boolean retainAll(Collection c)
278     {
279         return this.listData.retainAll(c);
280     }
281 
282     /***
283      * Returns a compile-time typesafe version of this list.  Unlike this
284      * List, the returned list will not accept String values as elements.
285      * 
286      * @return  a typesafe version of this list
287      */
288     public List<T> typesafe() {
289         return listData;
290     }
291 
292     private class ListIter implements ListIterator<Object> {
293 
294         final private ListIterator<T> delegate;
295 
296         public ListIter() {
297             this.delegate = listData.listIterator();
298         }
299 
300         public ListIter(int index) {
301             this.delegate = listData.listIterator(index);
302         }
303 
304         public void add(Object o) {
305             T checked = checkType(o);
306             delegate.add(checked);
307         }
308 
309         public boolean hasNext() {
310             return delegate.hasNext();
311         }
312 
313         public boolean hasPrevious() {
314             return delegate.hasPrevious();
315         }
316 
317         public Object next() {
318             return delegate.next();
319         }
320 
321         public int nextIndex() {
322             return delegate.nextIndex();
323         }
324 
325         public Object previous() {
326             return delegate.previous();
327         }
328 
329         public int previousIndex() {
330             return delegate.previousIndex();
331         }
332 
333         public void remove() {
334             delegate.remove();
335         }
336 
337         public void set(Object o) {
338             T checked = checkType(o);
339             delegate.set(checked);
340         }
341 
342     }
343 }