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 */
018
019package org.apache.hadoop.record;
020
021import java.io.UnsupportedEncodingException;
022
023import org.apache.hadoop.classification.InterfaceAudience;
024import org.apache.hadoop.classification.InterfaceStability;
025
026/**
027 * A byte sequence that is used as a Java native type for buffer.
028 * It is resizable and distinguishes between the count of the seqeunce and
029 * the current capacity.
030 * 
031 * @deprecated Replaced by <a href="https://hadoop.apache.org/avro/">Avro</a>.
032 */
033@Deprecated
034@InterfaceAudience.Public
035@InterfaceStability.Stable
036public class Buffer implements Comparable, Cloneable {
037  /** Number of valid bytes in this.bytes. */
038  private int count;
039  /** Backing store for Buffer. */
040  private byte[] bytes = null;
041
042  /**
043   * Create a zero-count sequence.
044   */
045  public Buffer() {
046    this.count = 0;
047  }
048
049  /**
050   * Create a Buffer using the byte array as the initial value.
051   *
052   * @param bytes This array becomes the backing storage for the object.
053   */
054  public Buffer(byte[] bytes) {
055    this.bytes = bytes;
056    this.count = (bytes == null) ? 0 : bytes.length;
057  }
058  
059  /**
060   * Create a Buffer using the byte range as the initial value.
061   *
062   * @param bytes Copy of this array becomes the backing storage for the object.
063   * @param offset offset into byte array
064   * @param length length of data
065   */
066  public Buffer(byte[] bytes, int offset, int length) {
067    copy(bytes, offset, length);
068  }
069  
070  
071  /**
072   * Use the specified bytes array as underlying sequence.
073   *
074   * @param bytes byte sequence
075   */
076  public void set(byte[] bytes) {
077    this.count = (bytes == null) ? 0 : bytes.length;
078    this.bytes = bytes;
079  }
080  
081  /**
082   * Copy the specified byte array to the Buffer. Replaces the current buffer.
083   *
084   * @param bytes byte array to be assigned
085   * @param offset offset into byte array
086   * @param length length of data
087   */
088  public final void copy(byte[] bytes, int offset, int length) {
089    if (this.bytes == null || this.bytes.length < length) {
090      this.bytes = new byte[length];
091    }
092    System.arraycopy(bytes, offset, this.bytes, 0, length);
093    this.count = length;
094  }
095  
096  /**
097   * Get the data from the Buffer.
098   * 
099   * @return The data is only valid between 0 and getCount() - 1.
100   */
101  public byte[] get() {
102    if (bytes == null) {
103      bytes = new byte[0];
104    }
105    return bytes;
106  }
107  
108  /**
109   * Get the current count of the buffer.
110   */
111  public int getCount() {
112    return count;
113  }
114  
115  /**
116   * Get the capacity, which is the maximum count that could handled without
117   * resizing the backing storage.
118   * 
119   * @return The number of bytes
120   */
121  public int getCapacity() {
122    return this.get().length;
123  }
124  
125  /**
126   * Change the capacity of the backing storage.
127   * The data is preserved if newCapacity >= getCount().
128   * @param newCapacity The new capacity in bytes.
129   */
130  public void setCapacity(int newCapacity) {
131    if (newCapacity < 0) {
132      throw new IllegalArgumentException("Invalid capacity argument "+newCapacity); 
133    }
134    if (newCapacity == 0) {
135      this.bytes = null;
136      this.count = 0;
137      return;
138    }
139    if (newCapacity != getCapacity()) {
140      byte[] data = new byte[newCapacity];
141      if (newCapacity < count) {
142        count = newCapacity;
143      }
144      if (count != 0) {
145        System.arraycopy(this.get(), 0, data, 0, count);
146      }
147      bytes = data;
148    }
149  }
150  
151  /**
152   * Reset the buffer to 0 size
153   */
154  public void reset() {
155    setCapacity(0);
156  }
157  
158  /**
159   * Change the capacity of the backing store to be the same as the current 
160   * count of buffer.
161   */
162  public void truncate() {
163    setCapacity(count);
164  }
165  
166  /**
167   * Append specified bytes to the buffer.
168   *
169   * @param bytes byte array to be appended
170   * @param offset offset into byte array
171   * @param length length of data
172
173  */
174  public void append(byte[] bytes, int offset, int length) {
175    setCapacity(count+length);
176    System.arraycopy(bytes, offset, this.get(), count, length);
177    count = count + length;
178  }
179  
180  /**
181   * Append specified bytes to the buffer
182   *
183   * @param bytes byte array to be appended
184   */
185  public void append(byte[] bytes) {
186    append(bytes, 0, bytes.length);
187  }
188  
189  // inherit javadoc
190  @Override
191  public int hashCode() {
192    int hash = 1;
193    byte[] b = this.get();
194    for (int i = 0; i < count; i++)
195      hash = (31 * hash) + b[i];
196    return hash;
197  }
198  
199  /**
200   * Define the sort order of the Buffer.
201   * 
202   * @param other The other buffer
203   * @return Positive if this is bigger than other, 0 if they are equal, and
204   *         negative if this is smaller than other.
205   */
206  @Override
207  public int compareTo(Object other) {
208    Buffer right = ((Buffer) other);
209    byte[] lb = this.get();
210    byte[] rb = right.get();
211    for (int i = 0; i < count && i < right.count; i++) {
212      int a = (lb[i] & 0xff);
213      int b = (rb[i] & 0xff);
214      if (a != b) {
215        return a - b;
216      }
217    }
218    return count - right.count;
219  }
220  
221  // inherit javadoc
222  @Override
223  public boolean equals(Object other) {
224    if (other instanceof Buffer && this != other) {
225      return compareTo(other) == 0;
226    }
227    return (this == other);
228  }
229  
230  // inheric javadoc
231  @Override
232  public String toString() {
233    StringBuilder sb = new StringBuilder(2*count);
234    for(int idx = 0; idx < count; idx++) {
235      sb.append(Character.forDigit((bytes[idx] & 0xF0) >> 4, 16));
236      sb.append(Character.forDigit(bytes[idx] & 0x0F, 16));
237    }
238    return sb.toString();
239  }
240  
241  /**
242   * Convert the byte buffer to a string an specific character encoding
243   *
244   * @param charsetName Valid Java Character Set Name
245   */
246  public String toString(String charsetName)
247    throws UnsupportedEncodingException {
248    return new String(this.get(), 0, this.getCount(), charsetName);
249  }
250  
251  // inherit javadoc
252  @Override
253  public Object clone() throws CloneNotSupportedException {
254    Buffer result = (Buffer) super.clone();
255    result.copy(this.get(), 0, this.getCount());
256    return result;
257  }
258}