1   /**
2    * Copyright 2007 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.*;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import junit.framework.TestCase;
27  
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.hbase.HBaseConfiguration;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.filter.Filter;
32  import org.apache.hadoop.hbase.filter.FilterBase;
33  import org.apache.hadoop.hbase.filter.FilterList;
34  import org.apache.hadoop.hbase.filter.PrefixFilter;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.io.Text;
37  import org.apache.hadoop.io.Writable;
38  import org.apache.hadoop.io.WritableComparator;
39  import org.junit.Assert;
40  
41  public class TestHbaseObjectWritable extends TestCase {
42  
43    @Override
44    protected void setUp() throws Exception {
45      super.setUp();
46    }
47  
48    @Override
49    protected void tearDown() throws Exception {
50      super.tearDown();
51    }
52  
53    @SuppressWarnings("boxing")
54    public void testReadOldObjectDataInput() throws IOException {
55      Configuration conf = HBaseConfiguration.create();
56      /*
57       * This is the code used to generate byte[] where
58       *  HbaseObjectWritable used byte for code
59       * 
60      ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
61      DataOutputStream out = new DataOutputStream(byteStream);
62      HbaseObjectWritable.writeObject(out, bytes, byte[].class, conf);
63      byte[] ba = byteStream.toByteArray();
64      out.close();
65      */
66      
67      /*
68       * byte array generated by the folowing call
69       *  HbaseObjectWritable.writeObject(out, new Text("Old"), Text.class, conf);
70       */
71      byte[] baForText = {13, 13, 3, 79, 108, 100};
72      Text txt = (Text)readByteArray(conf, baForText);
73      Text oldTxt = new Text("Old");
74      assertEquals(txt, oldTxt);
75      
76      final byte A = 'A';
77      byte [] bytes = new byte[1];
78      bytes[0] = A;
79      /*
80       * byte array generated by the folowing call
81       *  HbaseObjectWritable.writeObject(out, bytes, byte[].class, conf);
82       */
83      byte[] baForByteArray = { 11, 1, 65 };
84      byte[] baOut = (byte[])readByteArray(conf, baForByteArray);
85      assertTrue(Bytes.equals(baOut, bytes));
86    }
87    
88    /*
89     * helper method which reads byte array using HbaseObjectWritable.readObject()
90     */
91    private Object readByteArray(final Configuration conf, final byte[] ba)
92    throws IOException {
93      ByteArrayInputStream bais =
94        new ByteArrayInputStream(ba);
95      DataInputStream dis = new DataInputStream(bais);
96      Object product = HbaseObjectWritable.readObject(dis, conf);
97      dis.close();
98      return product;
99    }
100   
101   @SuppressWarnings("boxing")
102   public void testReadObjectDataInputConfiguration() throws IOException {
103     Configuration conf = HBaseConfiguration.create();
104     // Do primitive type
105     final int COUNT = 101;
106     assertTrue(doType(conf, COUNT, int.class).equals(COUNT));
107     // Do array
108     final byte [] testing = "testing".getBytes();
109     byte [] result = (byte [])doType(conf, testing, testing.getClass());
110     assertTrue(WritableComparator.compareBytes(testing, 0, testing.length,
111        result, 0, result.length) == 0);
112     // Do unsupported type.
113     boolean exception = false;
114     try {
115       doType(conf, new Object(), Object.class);
116     } catch (UnsupportedOperationException uoe) {
117       exception = true;
118     }
119     assertTrue(exception);
120     // Try odd types
121     final byte A = 'A';
122     byte [] bytes = new byte[1];
123     bytes[0] = A;
124     Object obj = doType(conf, bytes, byte [].class);
125     assertTrue(((byte [])obj)[0] == A);
126     // Do 'known' Writable type.
127     obj = doType(conf, new Text(""), Text.class);
128     assertTrue(obj instanceof Text);
129     //List.class
130     List<String> list = new ArrayList<String>();
131     list.add("hello");
132     list.add("world");
133     list.add("universe");
134     obj = doType(conf, list, List.class);
135     assertTrue(obj instanceof List);
136     Assert.assertArrayEquals(list.toArray(), ((List)obj).toArray() );
137     //ArrayList.class
138     ArrayList<String> arr = new ArrayList<String>();
139     arr.add("hello");
140     arr.add("world");
141     arr.add("universe");
142     obj = doType(conf,  arr, ArrayList.class);
143     assertTrue(obj instanceof ArrayList);
144     Assert.assertArrayEquals(list.toArray(), ((ArrayList)obj).toArray() );
145     // Check that filters can be serialized
146     obj = doType(conf, new PrefixFilter(HConstants.EMPTY_BYTE_ARRAY),
147       PrefixFilter.class);
148     assertTrue(obj instanceof PrefixFilter);
149   }
150 
151   public void testCustomWritable() throws Exception {
152     Configuration conf = HBaseConfiguration.create();
153 
154     // test proper serialization of un-encoded custom writables
155     CustomWritable custom = new CustomWritable("test phrase");
156     Object obj = doType(conf, custom, CustomWritable.class);
157     assertTrue(obj instanceof Writable);
158     assertTrue(obj instanceof CustomWritable);
159     assertEquals("test phrase", ((CustomWritable)obj).getValue());
160 
161     // test proper serialization of a custom filter
162     CustomFilter filt = new CustomFilter("mykey");
163     FilterList filtlist = new FilterList(FilterList.Operator.MUST_PASS_ALL);
164     filtlist.addFilter(filt);
165     obj = doType(conf, filtlist, FilterList.class);
166     assertTrue(obj instanceof FilterList);
167     assertNotNull(((FilterList)obj).getFilters());
168     assertEquals(1, ((FilterList)obj).getFilters().size());
169     Filter child = ((FilterList)obj).getFilters().get(0);
170     assertTrue(child instanceof CustomFilter);
171     assertEquals("mykey", ((CustomFilter)child).getKey());
172   }
173   
174   public void testCustomSerializable() throws Exception {
175     Configuration conf = HBaseConfiguration.create();
176 
177     // test proper serialization of un-encoded serialized java objects
178     CustomSerializable custom = new CustomSerializable("test phrase");
179     Object obj = doType(conf, custom, CustomSerializable.class);
180     assertTrue(obj instanceof Serializable);
181     assertTrue(obj instanceof CustomSerializable);
182     assertEquals("test phrase", ((CustomSerializable)obj).getValue());
183   }
184 
185   private Object doType(final Configuration conf, final Object value,
186       final Class<?> clazz)
187   throws IOException {
188     ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
189     DataOutputStream out = new DataOutputStream(byteStream);
190     HbaseObjectWritable.writeObject(out, value, clazz, conf);
191     out.close();
192     ByteArrayInputStream bais =
193       new ByteArrayInputStream(byteStream.toByteArray());
194     DataInputStream dis = new DataInputStream(bais);
195     Object product = HbaseObjectWritable.readObject(dis, conf);
196     dis.close();
197     return product;
198   }
199   
200   public static class CustomSerializable implements Serializable {
201     private static final long serialVersionUID = 1048445561865740632L;
202     private String value = null;
203     
204     public CustomSerializable() {
205     }
206     
207     public CustomSerializable(String value) {
208       this.value = value;
209     }
210     
211     public String getValue() {
212       return value;
213     }
214     
215     public void setValue(String value) {
216       this.value = value;
217     }
218     
219   }
220 
221   public static class CustomWritable implements Writable {
222     private String value = null;
223 
224     public CustomWritable() {
225     }
226 
227     public CustomWritable(String val) {
228       this.value = val;
229     }
230 
231     public String getValue() { return value; }
232 
233     @Override
234     public void write(DataOutput out) throws IOException {
235       Text.writeString(out, this.value);
236     }
237 
238     @Override
239     public void readFields(DataInput in) throws IOException {
240       this.value = Text.readString(in);
241     }
242   }
243 
244   public static class CustomFilter extends FilterBase {
245     private String key = null;
246 
247     public CustomFilter() {
248     }
249 
250     public CustomFilter(String key) {
251       this.key = key;
252     }
253 
254     public String getKey() { return key; }
255 
256     public void write(DataOutput out) throws IOException {
257       Text.writeString(out, this.key);
258     }
259 
260     public void readFields(DataInput in) throws IOException {
261       this.key = Text.readString(in);
262     }
263   }
264 }