001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.io;
019
020import java.io.DataInput;
021import java.io.DataOutput;
022import java.io.IOException;
023import java.util.Collection;
024import java.util.Comparator;
025import java.util.Map;
026import java.util.Set;
027import java.util.SortedMap;
028import java.util.TreeMap;
029
030import org.apache.hadoop.classification.InterfaceAudience;
031import org.apache.hadoop.classification.InterfaceStability;
032import org.apache.hadoop.util.ReflectionUtils;
033
034/**
035 * A Writable SortedMap.
036 */
037@InterfaceAudience.Public
038@InterfaceStability.Stable
039public class SortedMapWritable<K extends WritableComparable<? super K>> extends AbstractMapWritable
040  implements SortedMap<K, Writable> {
041  
042  private SortedMap<K, Writable> instance;
043  
044  /** default constructor. */
045  public SortedMapWritable() {
046    super();
047    this.instance = new TreeMap<K, Writable>();
048  }
049  
050  /**
051   * Copy constructor.
052   * 
053   * @param other the map to copy from
054   */
055  public SortedMapWritable(SortedMapWritable<K> other) {
056    this();
057    copy(other);
058  }
059
060  @Override
061  public Comparator<? super K> comparator() {
062    // Returning null means we use the natural ordering of the keys
063    return null;
064  }
065
066  @Override
067  public K firstKey() {
068    return instance.firstKey();
069  }
070
071  @Override
072  public SortedMap<K, Writable> headMap(K toKey) {
073    return instance.headMap(toKey);
074  }
075
076  @Override
077  public K lastKey() {
078    return instance.lastKey();
079  }
080
081  @Override
082  public SortedMap<K, Writable> subMap(K fromKey, K toKey) {
083    return instance.subMap(fromKey, toKey);
084  }
085
086  @Override
087  public SortedMap<K, Writable> tailMap(K fromKey) {
088    return instance.tailMap(fromKey);
089  }
090
091  @Override
092  public void clear() {
093    instance.clear();
094  }
095
096  @Override
097  public boolean containsKey(Object key) {
098    return instance.containsKey(key);
099  }
100
101  @Override
102  public boolean containsValue(Object value) {
103    return instance.containsValue(value);
104  }
105
106  @Override
107  public Set<Map.Entry<K, Writable>> entrySet() {
108    return instance.entrySet();
109  }
110
111  @Override
112  public Writable get(Object key) {
113    return instance.get(key);
114  }
115
116  @Override
117  public boolean isEmpty() {
118    return instance.isEmpty();
119  }
120
121  @Override
122  public Set<K> keySet() {
123    return instance.keySet();
124  }
125
126  @Override
127  public Writable put(K key, Writable value) {
128    addToMap(key.getClass());
129    addToMap(value.getClass());
130    return instance.put(key, value);
131  }
132
133  @Override
134  public void putAll(Map<? extends K, ? extends Writable> t) {
135    for (Map.Entry<? extends K, ? extends Writable> e:
136      t.entrySet()) {
137      put(e.getKey(), e.getValue());
138    }
139  }
140
141  @Override
142  public Writable remove(Object key) {
143    return instance.remove(key);
144  }
145
146  @Override
147  public int size() {
148    return instance.size();
149  }
150
151  @Override
152  public Collection<Writable> values() {
153    return instance.values();
154  }
155
156  @SuppressWarnings("unchecked")
157  @Override
158  public void readFields(DataInput in) throws IOException {
159    super.readFields(in);
160    
161    // Read the number of entries in the map
162    
163    int entries = in.readInt();
164    
165    // Then read each key/value pair
166    
167    for (int i = 0; i < entries; i++) {
168      K key =
169        (K) ReflectionUtils.newInstance(getClass(
170            in.readByte()), getConf());
171      
172      key.readFields(in);
173      
174      Writable value = (Writable) ReflectionUtils.newInstance(getClass(
175          in.readByte()), getConf());
176      
177      value.readFields(in);
178      instance.put(key, value);
179    }
180  }
181
182  @Override
183  public void write(DataOutput out) throws IOException {
184    super.write(out);
185    
186    // Write out the number of entries in the map
187    
188    out.writeInt(instance.size());
189    
190    // Then write out each key/value pair
191    
192    for (Map.Entry<K, Writable> e: instance.entrySet()) {
193      out.writeByte(getId(e.getKey().getClass()));
194      e.getKey().write(out);
195      out.writeByte(getId(e.getValue().getClass()));
196      e.getValue().write(out);
197    }
198  }
199
200  @Override
201  public boolean equals(Object obj) {
202    if (this == obj) {
203      return true;
204    }
205
206    if (obj instanceof SortedMapWritable) {
207      Map<?,?> map = (Map<?,?>) obj;
208      if (size() != map.size()) {
209        return false;
210      }
211
212      return entrySet().equals(map.entrySet());
213    }
214
215    return false;
216  }
217
218  @Override
219  public int hashCode() {
220    return instance.hashCode();
221  }
222}