View Javadoc

1   /**
2    * Copyright 2008 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.io;
21  
22  import java.io.DataInput;
23  import java.io.DataOutput;
24  import java.io.IOException;
25  import java.util.Collection;
26  import java.util.Comparator;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.SortedMap;
30  import java.util.TreeMap;
31  import java.util.concurrent.atomic.AtomicReference;
32  
33  import org.apache.hadoop.conf.Configurable;
34  import org.apache.hadoop.conf.Configuration;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.io.Writable;
37  import org.apache.hadoop.util.ReflectionUtils;
38  
39  /**
40   * A Writable Map.
41   * Like {@link org.apache.hadoop.io.MapWritable} but dumb. It will fail
42   * if passed a value type that it has not already been told about. Its  been
43   * primed with hbase Writables and byte [].  Keys are always byte arrays.
44   *
45   * @param <K> <byte []> key  TODO: Parameter K is never used, could be removed.
46   * @param <V> value Expects a Writable or byte [].
47   */
48  public class HbaseMapWritable <K,V>
49  implements SortedMap<byte[],V>, Configurable, Writable, CodeToClassAndBack{
50    private AtomicReference<Configuration> conf = null;
51    protected SortedMap<byte [], V> instance = null;
52  
53    /**
54     * The default contructor where a TreeMap is used
55     **/
56     public HbaseMapWritable(){
57       this (new TreeMap<byte [], V>(Bytes.BYTES_COMPARATOR));
58     }
59  
60    /**
61     * Contructor where another SortedMap can be used
62     *
63     * @param map the SortedMap to be used
64     */
65    public HbaseMapWritable(SortedMap<byte[], V> map){
66      conf = new AtomicReference<Configuration>();
67      instance = map;
68    }
69  
70  
71    /** @return the conf */
72    public Configuration getConf() {
73      return conf.get();
74    }
75  
76    /** @param conf the conf to set */
77    public void setConf(Configuration conf) {
78      this.conf.set(conf);
79    }
80  
81    public void clear() {
82      instance.clear();
83    }
84  
85    public boolean containsKey(Object key) {
86      return instance.containsKey(key);
87    }
88  
89    public boolean containsValue(Object value) {
90      return instance.containsValue(value);
91    }
92  
93    public Set<Entry<byte [], V>> entrySet() {
94      return instance.entrySet();
95    }
96  
97    public V get(Object key) {
98      return instance.get(key);
99    }
100 
101   public boolean isEmpty() {
102     return instance.isEmpty();
103   }
104 
105   public Set<byte []> keySet() {
106     return instance.keySet();
107   }
108 
109   public int size() {
110     return instance.size();
111   }
112 
113   public Collection<V> values() {
114     return instance.values();
115   }
116 
117   public void putAll(Map<? extends byte [], ? extends V> m) {
118     this.instance.putAll(m);
119   }
120 
121   public V remove(Object key) {
122     return this.instance.remove(key);
123   }
124 
125   public V put(byte [] key, V value) {
126     return this.instance.put(key, value);
127   }
128 
129   public Comparator<? super byte[]> comparator() {
130     return this.instance.comparator();
131   }
132 
133   public byte[] firstKey() {
134     return this.instance.firstKey();
135   }
136 
137   public SortedMap<byte[], V> headMap(byte[] toKey) {
138     return this.instance.headMap(toKey);
139   }
140 
141   public byte[] lastKey() {
142     return this.instance.lastKey();
143   }
144 
145   public SortedMap<byte[], V> subMap(byte[] fromKey, byte[] toKey) {
146     return this.instance.subMap(fromKey, toKey);
147   }
148 
149   public SortedMap<byte[], V> tailMap(byte[] fromKey) {
150     return this.instance.tailMap(fromKey);
151   }
152 
153   // Writable
154 
155   /** @return the Class class for the specified id */
156   @SuppressWarnings("boxing")
157   protected Class<?> getClass(byte id) {
158     return CODE_TO_CLASS.get(id);
159   }
160 
161   /** @return the id for the specified Class */
162   @SuppressWarnings("boxing")
163   protected byte getId(Class<?> clazz) {
164     Byte b = CLASS_TO_CODE.get(clazz);
165     if (b == null) {
166       throw new NullPointerException("Nothing for : " + clazz);
167     }
168     return b;
169   }
170 
171   /**
172    * @see java.lang.Object#toString()
173    */
174   @Override
175   public String toString() {
176     return this.instance.toString();
177   }
178 
179   public void write(DataOutput out) throws IOException {
180     // Write out the number of entries in the map
181     out.writeInt(this.instance.size());
182     // Then write out each key/value pair
183     for (Map.Entry<byte [], V> e: instance.entrySet()) {
184       Bytes.writeByteArray(out, e.getKey());
185       Byte id = getId(e.getValue().getClass());
186       out.writeByte(id);
187       Object value = e.getValue();
188       if (value instanceof byte []) {
189         Bytes.writeByteArray(out, (byte [])value);
190       } else {
191         ((Writable)value).write(out);
192       }
193     }
194   }
195 
196   @SuppressWarnings("unchecked")
197   public void readFields(DataInput in) throws IOException {
198     // First clear the map.  Otherwise we will just accumulate
199     // entries every time this method is called.
200     this.instance.clear();
201     // Read the number of entries in the map
202     int entries = in.readInt();
203     // Then read each key/value pair
204     for (int i = 0; i < entries; i++) {
205       byte [] key = Bytes.readByteArray(in);
206       byte id = in.readByte();
207       Class clazz = getClass(id);
208       V value = null;
209       if (clazz.equals(byte [].class)) {
210         byte [] bytes = Bytes.readByteArray(in);
211         value = (V)bytes;
212       } else {
213         Writable w = (Writable)ReflectionUtils.
214           newInstance(clazz, getConf());
215         w.readFields(in);
216         value = (V)w;
217       }
218       this.instance.put(key, value);
219     }
220   }
221 }