View Javadoc

1   /**
2    * Copyright 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;
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import org.apache.hadoop.classification.InterfaceAudience;
26  import org.apache.hadoop.classification.InterfaceStability;
27  import org.apache.hadoop.hbase.util.Bytes;
28  /**
29   * Tags are part of cells and helps to add metadata about the KVs.
30   * Metadata could be ACLs per cells, visibility labels, etc.
31   */
32  @InterfaceAudience.Private
33  @InterfaceStability.Evolving
34  public class Tag {
35    public final static int TYPE_LENGTH_SIZE = Bytes.SIZEOF_BYTE;
36    public final static int TAG_LENGTH_SIZE = Bytes.SIZEOF_SHORT;
37    public final static int INFRASTRUCTURE_SIZE = TYPE_LENGTH_SIZE + TAG_LENGTH_SIZE;
38  
39    private final byte type;
40    private final byte[] bytes;
41    private int offset = 0;
42    private short length = 0;
43  
44    // The special tag will write the length of each tag and that will be
45    // followed by the type and then the actual tag.
46    // So every time the length part is parsed we need to add + 1 byte to it to
47    // get the type and then get the actual tag.
48    public Tag(byte tagType, String tag) {
49      this(tagType, Bytes.toBytes(tag));
50    }
51  
52    /**
53     * @param tagType
54     * @param tag
55     */
56    public Tag(byte tagType, byte[] tag) {
57      /** <length of tag - 2 bytes><type code - 1 byte><tag>
58       * taglength maximum is Short.MAX_SIZE.  It includes 1 byte type length and actual tag bytes length.
59       */
60      short tagLength = (short) ((tag.length & 0x0000ffff) + TYPE_LENGTH_SIZE);
61      length = (short) (TAG_LENGTH_SIZE + tagLength);
62      bytes = new byte[length];
63      int pos = Bytes.putShort(bytes, 0, tagLength);
64      pos = Bytes.putByte(bytes, pos, tagType);
65      Bytes.putBytes(bytes, pos, tag, 0, tag.length);
66      this.type = tagType;
67    }
68  
69    /**
70     * Creates a Tag from the specified byte array and offset. Presumes
71     * <code>bytes</code> content starting at <code>offset</code> is formatted as
72     * a Tag blob.
73     * The bytes to include the tag type, tag length and actual tag bytes.
74     * @param bytes
75     *          byte array
76     * @param offset
77     *          offset to start of Tag
78     */
79    public Tag(byte[] bytes, int offset) {
80      this(bytes, offset, getLength(bytes, offset));
81    }
82  
83    private static short getLength(byte[] bytes, int offset) {
84      return (short) (TAG_LENGTH_SIZE + Bytes.toShort(bytes, offset));
85    }
86  
87    /**
88     * Creates a Tag from the specified byte array, starting at offset, and for
89     * length <code>length</code>. Presumes <code>bytes</code> content starting at
90     * <code>offset</code> is formatted as a Tag blob.
91     * @param bytes
92     *          byte array
93     * @param offset
94     *          offset to start of the Tag
95     * @param length
96     *          length of the Tag
97     */
98    public Tag(byte[] bytes, int offset, short length) {
99      this.bytes = bytes;
100     this.offset = offset;
101     this.length = length;
102     this.type = bytes[offset + TAG_LENGTH_SIZE];
103   }
104 
105   /**
106    * @return The byte array backing this Tag.
107    */
108   public byte[] getBuffer() {
109     return this.bytes;
110   }
111 
112   /**
113    * @return the tag type
114    */
115   public byte getType() {
116     return this.type;
117   }
118 
119   /**
120    * @return Length of actual tag bytes within the backed buffer
121    */
122   public int getTagLength() {
123     return this.length - INFRASTRUCTURE_SIZE;
124   }
125 
126   /**
127    * @return Offset of actual tag bytes within the backed buffer
128    */
129   public int getTagOffset() {
130     return this.offset + INFRASTRUCTURE_SIZE;
131   }
132 
133   public byte[] getValue() {
134     int tagLength = getTagLength();
135     byte[] tag = new byte[tagLength];
136     Bytes.putBytes(tag, 0, bytes, getTagOffset(), tagLength);
137     return tag;
138   }
139 
140   /**
141    * Creates the list of tags from the byte array b. Expected that b is in the
142    * expected tag format
143    * @param b
144    * @param offset
145    * @param length
146    * @return List of tags
147    */
148   public static List<Tag> asList(byte[] b, int offset, int length) {
149     List<Tag> tags = new ArrayList<Tag>();
150     int pos = offset;
151     while (pos < offset + length) {
152       short tagLen = Bytes.toShort(b, pos);
153       tags.add(new Tag(b, pos, (short) (tagLen + TAG_LENGTH_SIZE)));
154       pos += TAG_LENGTH_SIZE + tagLen;
155     }
156     return tags;
157   }
158   
159   /**
160    * Retrieve the first tag from the tags byte array matching the passed in tag type
161    * @param b
162    * @param offset
163    * @param length
164    * @param type
165    * @return null if there is no tag of the passed in tag type
166    */
167   public static Tag getTag(byte[] b, int offset, int length, byte type) {
168     int pos = offset;
169     while (pos < offset + length) {
170       short tagLen = Bytes.toShort(b, pos);
171       if(b[pos + TAG_LENGTH_SIZE] == type) {
172         return new Tag(b, pos, (short) (tagLen + TAG_LENGTH_SIZE));
173       }
174       pos += TAG_LENGTH_SIZE + tagLen;
175     }
176     return null;
177   }
178 
179   /**
180    * Returns the total length of the entire tag entity
181    */
182   short getLength() {
183     return this.length;
184   }
185 
186   /**
187    * Returns the offset of the entire tag entity
188    */
189   int getOffset() {
190     return this.offset;
191   }
192 }