source: sample/hadoop-0.16/tw/org/nchc/tuple/ListWritable.java @ 243

Last change on this file since 243 was 21, checked in by waue, 16 years ago

hadoop 0.16

File size: 10.9 KB
Line 
1/*
2 * Cloud9: A MapReduce Library for Hadoop
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you
5 * may not use this file except in compliance with the License. You may
6 * obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 * implied. See the License for the specific language governing
14 * permissions and limitations under the License.
15 */
16
17package tw.org.nchc.tuple;
18
19import java.io.ByteArrayInputStream;
20import java.io.ByteArrayOutputStream;
21import java.io.DataInput;
22import java.io.DataInputStream;
23import java.io.DataOutput;
24import java.io.DataOutputStream;
25import java.io.IOException;
26import java.util.ArrayList;
27import java.util.Collection;
28import java.util.Iterator;
29import java.util.List;
30import java.util.ListIterator;
31
32import org.apache.hadoop.io.WritableComparable;
33
34/**
35 * <p>
36 * Class that represents a list in Hadoop's data type system. Elements in the
37 * list must be homogeneous and must implement Hadoop's WritableComparable
38 * interface. This class, combined with {@link Tuple}, allows the user to
39 * define arbitrarily complex data structures.
40 * </p>
41 *
42 * @see Tuple
43 * @param <E>
44 *            type of list element
45 */
46public class ListWritable<E extends WritableComparable> implements WritableComparable, Iterable<E>, List<E> {
47
48  private List<E> mList;
49
50  private Class<?> listElementClass;
51
52  /**
53   * Creates a ListWritable object.
54   */
55  public ListWritable() {
56    mList = new ArrayList<E>();
57  }
58
59  /**
60   * Appends the specified element to the end of this list.
61   *
62   * @param e
63   *            element to be appended to this list
64   */
65  public boolean add(E e) {
66    if (mList.size() == 0) 
67      listElementClass = e.getClass();
68    else if (!e.getClass().equals(listElementClass))
69      throw new IllegalArgumentException("Cannot add element of type " + e.getClass().getCanonicalName() + " to list of type " + listElementClass.getCanonicalName());
70    return mList.add(e);
71  }
72
73  /**
74   * Returns the element at the specified position in this list
75   *
76   * @param index
77   *            index of the element to return
78   * @return the element at the specified position in this list
79   */
80  public E get(int index) {
81    if (index < 0 || index >= mList.size()) {
82      throw new IndexOutOfBoundsException();
83    }
84
85    return mList.get(index);
86  }
87
88  /**
89   * Removes all elements from this list.
90   */
91  public void clear() {
92    mList.clear();
93  }
94
95  /**
96   * Replaces the element at the specified position in this list with the
97   * specified element.
98   *
99   * @param index
100   *            index of the element to replace
101   * @param element
102   *            element to be stored at the specified position
103   */
104  public E set(int index, E element) {
105        if(mList.size() > 0 && !element.getClass().equals(listElementClass)) {
106      throw new IllegalArgumentException("Cannot add element of type " + element.getClass().getCanonicalName() + " to list of type " + listElementClass.getCanonicalName());
107        }
108    return mList.set(index, element);
109  }
110
111  /**
112   * Returns the number of elements in this list.
113   *
114   * @return the number of elements in this list
115   */
116  public int size() {
117    return mList.size();
118  }
119
120  /**
121   * Deserializes the Tuple.
122   *
123   * @param in
124   *            source for raw byte representation
125   */
126  @SuppressWarnings("unchecked")
127  public void readFields(DataInput in) throws IOException {
128
129    mList.clear();
130
131    int numFields = in.readInt();
132    String className = in.readUTF();
133    E obj;
134    try {
135      Class c = Class.forName(className);
136      listElementClass = c;
137
138      for (int i = 0; i < numFields; i++) {
139        obj = (E) c.newInstance();
140        int sz = in.readInt();
141        byte[] bytes = new byte[sz];
142        in.readFully(bytes);
143
144        obj.readFields(new DataInputStream(new ByteArrayInputStream(bytes)));
145        this.add(obj);
146      }
147
148    } catch (ClassNotFoundException e) {
149      e.printStackTrace();
150    } catch (IllegalAccessException e) {
151      e.printStackTrace();
152    } catch (InstantiationException e) {
153      e.printStackTrace();
154    }
155  }
156
157  /**
158   * Serializes this Tuple.
159   *
160   * @param out
161   *            where to write the raw byte representation
162   */
163  public void write(DataOutput out) throws IOException {
164    out.writeInt(mList.size());
165    if (mList.size() > 0)
166      out.writeUTF(listElementClass.getCanonicalName());
167    else
168      out.writeUTF(WritableComparable.class.getCanonicalName());
169
170    for (int i = 0; i < mList.size(); i++) {
171      if (mList.get(i) == null) {
172        throw new IOException("Cannot serialize null fields!");
173      }
174
175      ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
176      DataOutputStream dataOut = new DataOutputStream(bytesOut);
177
178      mList.get(i).write(dataOut);
179
180      out.writeInt(bytesOut.size());
181      out.write(bytesOut.toByteArray());
182    }
183  }
184
185  /**
186   * Generates human-readable String representation of this Tuple.
187   *
188   * @return human-readable String representation of this Tuple
189   */
190  public String toString() {
191    StringBuffer sb = new StringBuffer();
192    sb.append("[");
193    for (int i = 0; i < this.size(); i++) {
194      if (i != 0)
195        sb.append(", ");
196      sb.append(this.get(i));
197    }
198    sb.append("]");
199
200    return sb.toString();
201  }
202
203  /**
204   * <p>
205   * Defines a natural sort order for the ListWritable class. Following
206   * standard convention, this method returns a value less than zero, a value
207   * greater than zero, or zero if this ListWritable should be sorted before,
208   * sorted after, or is equal to <code>obj</code>. The sort order is
209   * defined as follows:
210   * </p>
211   *
212   * <ul>
213   * <li>Each element in the list is compared sequentially from first to
214   * last.</li>
215   * <li>Lists are sorted with respect to the natural order of the current
216   * list element under consideration, by calling its <code>compareTo</code>
217   * method.</li>
218   * <li>If the current list elements are equal, the next set of elements are
219   * considered.</li>
220   * <li>If all compared elements are equal, but lists are different lengths,
221   * the shorter list is sorted first.</li>
222   * <li>If all list elements are equal and the lists are equal in length,
223   * then the lists are considered equal</li>
224   * </ul>
225   *
226   * @return a value less than zero, a value greater than zero, or zero if
227   *         this Tuple should be sorted before, sorted after, or is equal to
228   *         <code>obj</code>.
229   */
230  public int compareTo(Object obj) {
231    ListWritable<?> that = (ListWritable<?>) obj;
232
233    // iterate through the fields
234    for (int i = 0; i < this.size(); i++) {
235      // sort shorter list first
236      if (i >= that.size())
237        return 1;
238
239      @SuppressWarnings("unchecked")
240      Comparable<Object> thisField = this.get(i);
241      @SuppressWarnings("unchecked")
242      Comparable<Object> thatField = that.get(i);
243
244      if (thisField.equals(thatField)) {
245        // if we're down to the last field, sort shorter list first
246        if (i == this.size() - 1) {
247          if (this.size() > that.size())
248            return 1;
249
250          if (this.size() < that.size())
251            return -1;
252        }
253        // otherwise, move to next field
254      } else {
255        return thisField.compareTo(thatField);
256      }
257    }
258
259    return 0;
260  }
261
262  /**
263   * @return an iterator over the elements in this list in proper sequence.
264   */
265  public Iterator<E> iterator() {
266    return this.mList.iterator();
267  }
268
269  /* (non-Javadoc)
270   * @see java.util.List#add(int, java.lang.Object)
271   */
272  public void add(int pos, E element) {
273   
274        if(mList.size() > 0 && !element.getClass().equals(listElementClass)) {
275      throw new IllegalArgumentException("Cannot add element of type " + element.getClass().getCanonicalName() + " to list of type " + listElementClass.getCanonicalName());
276        }
277    mList.add(pos, element);
278  }
279
280  /* (non-Javadoc)
281   * @see java.util.List#addAll(java.util.Collection)
282   */
283  public boolean addAll(Collection<? extends E> elements) {
284    boolean failure = false;
285    Iterator<? extends E> it = elements.iterator();
286    while (it.hasNext()) {
287      E obj = it.next();
288      if (mList.size() == 0) 
289        listElementClass = obj.getClass();
290      else if (!obj.getClass().equals(listElementClass))
291        throw new IllegalArgumentException("Cannot add element of type " + obj.getClass().getCanonicalName() + " to list of type " + listElementClass.getCanonicalName());
292     
293      if (!mList.add(obj)) failure = true;
294    }
295   
296   
297    return !failure;
298  }
299
300  /* (non-Javadoc)
301   * @see java.util.List#addAll(int, java.util.Collection)
302   */
303  public boolean addAll(int pos, Collection<? extends E> elements) {
304    // TODO: Check the return type of this method.
305    Iterator<? extends E> it = elements.iterator();
306    int curPos = pos;
307    while (it.hasNext()) {
308      E obj = it.next();
309      if (mList.size() == 0) 
310        listElementClass = obj.getClass();
311      else if (!obj.getClass().equals(listElementClass))
312        throw new IllegalArgumentException("Cannot add element of type " + obj.getClass().getCanonicalName() + " to list of type " + listElementClass.getCanonicalName());
313     
314      mList.add(curPos, obj);
315      ++curPos;
316    }
317   
318   
319    return true;
320  }
321
322  /* (non-Javadoc)
323   * @see java.util.List#contains(java.lang.Object)
324   */
325  public boolean contains(Object element) {
326    return mList.contains(element);
327  }
328
329  /* (non-Javadoc)
330   * @see java.util.List#containsAll(java.util.Collection)
331   */
332  public boolean containsAll(Collection<?> elements) {
333    return mList.containsAll(elements);
334  }
335
336  /* (non-Javadoc)
337   * @see java.util.List#indexOf(java.lang.Object)
338   */
339  public int indexOf(Object element) {
340    return mList.indexOf(element);
341  }
342
343  /* (non-Javadoc)
344   * @see java.util.List#isEmpty()
345   */
346  public boolean isEmpty() {
347    return mList.isEmpty();
348  }
349
350  /* (non-Javadoc)
351   * @see java.util.List#lastIndexOf(java.lang.Object)
352   */
353  public int lastIndexOf(Object element) {
354    return mList.lastIndexOf(element);
355  }
356
357  /* (non-Javadoc)
358   * @see java.util.List#listIterator()
359   */
360  public ListIterator<E> listIterator() {
361    return mList.listIterator();
362  }
363
364  /* (non-Javadoc)
365   * @see java.util.List#listIterator(int)
366   */
367  public ListIterator<E> listIterator(int arg0) {
368    return mList.listIterator(arg0);
369  }
370
371  /* (non-Javadoc)
372   * @see java.util.List#remove(java.lang.Object)
373   */
374  public boolean remove(Object element) {
375    return mList.remove(element);
376  }
377
378  /* (non-Javadoc)
379   * @see java.util.List#remove(int)
380   */
381  public E remove(int pos) {
382    return mList.remove(pos);
383  }
384
385  /* (non-Javadoc)
386   * @see java.util.List#removeAll(java.util.Collection)
387   */
388  public boolean removeAll(Collection<?> elements) {
389    return mList.removeAll(elements);
390  }
391
392  /* (non-Javadoc)
393   * @see java.util.List#retainAll(java.util.Collection)
394   */
395  public boolean retainAll(Collection<?> elements) {
396    return mList.retainAll(elements);
397  }
398
399  /* (non-Javadoc)
400   * @see java.util.List#subList(int, int)
401   */
402  public List<E> subList(int arg0, int arg1) {
403    // TODO Consider making this return a type of ListWritable rather than of ArrayList.
404    return mList.subList(arg0, arg1);
405  }
406
407  /* (non-Javadoc)
408   * @see java.util.List#toArray()
409   */
410  public Object[] toArray() {
411    return mList.toArray();
412  }
413
414  /* (non-Javadoc)
415   * @see java.util.List#toArray(T[])
416   */
417  public <T> T[] toArray(T[] arg0) {
418    return mList.toArray(arg0);
419  }
420
421}
Note: See TracBrowser for help on using the repository browser.