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    
019    package org.apache.hadoop.record;
020    
021    import java.io.UnsupportedEncodingException;
022    
023    import org.apache.hadoop.classification.InterfaceAudience;
024    import 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="http://hadoop.apache.org/avro/">Avro</a>.
032     */
033    @Deprecated
034    @InterfaceAudience.Public
035    @InterfaceStability.Stable
036    public 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) + (int)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    }