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.hbase.types; 019 020import org.apache.hadoop.hbase.util.Order; 021import org.apache.hadoop.hbase.util.PositionedByteRange; 022import org.apache.hadoop.hbase.util.SimplePositionedMutableByteRange; 023import org.apache.yetus.audience.InterfaceAudience; 024 025/** 026 * Wraps an existing {@link DataType} implementation as a fixed-length 027 * version of itself. This has the useful side-effect of turning an existing 028 * {@link DataType} which is not {@code skippable} into a {@code skippable} 029 * variant. 030 */ 031@InterfaceAudience.Public 032public class FixedLengthWrapper<T> implements DataType<T> { 033 034 protected final DataType<T> base; 035 protected final int length; 036 037 /** 038 * Create a fixed-length version of the {@code wrapped}. 039 * @param base the {@link DataType} to restrict to a fixed length. 040 * @param length the maximum length (in bytes) for encoded values. 041 */ 042 public FixedLengthWrapper(DataType<T> base, int length) { 043 this.base = base; 044 this.length = length; 045 } 046 047 /** 048 * Retrieve the maximum length (in bytes) of encoded values. 049 */ 050 public int getLength() { 051 return length; 052 } 053 054 @Override 055 public boolean isOrderPreserving() { 056 return base.isOrderPreserving(); 057 } 058 059 @Override 060 public Order getOrder() { 061 return base.getOrder(); 062 } 063 064 @Override 065 public boolean isNullable() { 066 return base.isNullable(); 067 } 068 069 @Override 070 public boolean isSkippable() { 071 return true; 072 } 073 074 @Override 075 public int encodedLength(T val) { 076 return length; 077 } 078 079 @Override 080 public Class<T> encodedClass() { 081 return base.encodedClass(); 082 } 083 084 @Override 085 public int skip(PositionedByteRange src) { 086 src.setPosition(src.getPosition() + this.length); 087 return this.length; 088 } 089 090 @Override 091 public T decode(PositionedByteRange src) { 092 if (src.getRemaining() < length) { 093 throw new IllegalArgumentException("Not enough buffer remaining. src.offset: " 094 + src.getOffset() + " src.length: " + src.getLength() + " src.position: " 095 + src.getPosition() + " max length: " + length); 096 } 097 // create a copy range limited to length bytes. boo. 098 PositionedByteRange b = new SimplePositionedMutableByteRange(length); 099 src.get(b.getBytes()); 100 return base.decode(b); 101 } 102 103 @Override 104 public int encode(PositionedByteRange dst, T val) { 105 if (dst.getRemaining() < length) { 106 throw new IllegalArgumentException("Not enough buffer remaining. dst.offset: " 107 + dst.getOffset() + " dst.length: " + dst.getLength() + " dst.position: " 108 + dst.getPosition() + " max length: " + length); 109 } 110 int written = base.encode(dst, val); 111 if (written > length) { 112 throw new IllegalArgumentException("Length of encoded value (" + written 113 + ") exceeds max length (" + length + ")."); 114 } 115 // TODO: is the zero-padding appropriate? 116 for (; written < length; written++) { 117 dst.put((byte) 0x00); 118 } 119 return written; 120 } 121}