View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.types;
19  
20  import org.apache.hadoop.hbase.classification.InterfaceAudience;
21  import org.apache.hadoop.hbase.classification.InterfaceStability;
22  import org.apache.hadoop.hbase.util.Order;
23  import org.apache.hadoop.hbase.util.PositionedByteRange;
24  import org.apache.hadoop.hbase.util.SimplePositionedMutableByteRange;
25  
26  /**
27   * Wraps an existing {@link DataType} implementation as a fixed-length
28   * version of itself. This has the useful side-effect of turning an existing
29   * {@link DataType} which is not {@code skippable} into a {@code skippable}
30   * variant.
31   */
32  @InterfaceAudience.Public
33  @InterfaceStability.Evolving
34  public class FixedLengthWrapper<T> implements DataType<T> {
35  
36    protected final DataType<T> base;
37    protected final int length;
38  
39    /**
40     * Create a fixed-length version of the {@code wrapped}.
41     * @param base the {@link DataType} to restrict to a fixed length.
42     * @param length the maximum length (in bytes) for encoded values.
43     */
44    public FixedLengthWrapper(DataType<T> base, int length) {
45      this.base = base;
46      this.length = length;
47    }
48  
49    /**
50     * Retrieve the maximum length (in bytes) of encoded values.
51     */
52    public int getLength() { return length; }
53  
54    @Override
55    public boolean isOrderPreserving() { return base.isOrderPreserving(); }
56  
57    @Override
58    public Order getOrder() { return base.getOrder(); }
59  
60    @Override
61    public boolean isNullable() { return base.isNullable(); }
62  
63    @Override
64    public boolean isSkippable() { return true; }
65  
66    @Override
67    public int encodedLength(T val) { return length; }
68  
69    @Override
70    public Class<T> encodedClass() { return base.encodedClass(); }
71  
72    @Override
73    public int skip(PositionedByteRange src) {
74      src.setPosition(src.getPosition() + this.length);
75      return this.length;
76    }
77  
78    @Override
79    public T decode(PositionedByteRange src) {
80      if (src.getRemaining() < length) {
81        throw new IllegalArgumentException("Not enough buffer remaining. src.offset: "
82            + src.getOffset() + " src.length: " + src.getLength() + " src.position: "
83            + src.getPosition() + " max length: " + length);
84      }
85      // create a copy range limited to length bytes. boo.
86      PositionedByteRange b = new SimplePositionedMutableByteRange(length);
87      src.get(b.getBytes());
88      return base.decode(b);
89    }
90  
91    @Override
92    public int encode(PositionedByteRange dst, T val) {
93      if (dst.getRemaining() < length) {
94        throw new IllegalArgumentException("Not enough buffer remaining. dst.offset: "
95            + dst.getOffset() + " dst.length: " + dst.getLength() + " dst.position: "
96            + dst.getPosition() + " max length: " + length);
97      }
98      int written = base.encode(dst, val);
99      if (written > length) {
100       throw new IllegalArgumentException("Length of encoded value (" + written
101           + ") exceeds max length (" + length + ").");
102     }
103     // TODO: is the zero-padding appropriate?
104     for (; written < length; written++) { dst.put((byte) 0x00); }
105     return written;
106   }
107 }